001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.model;
018
019import javax.xml.bind.annotation.XmlAccessType;
020import javax.xml.bind.annotation.XmlAccessorType;
021import javax.xml.bind.annotation.XmlAttribute;
022import javax.xml.bind.annotation.XmlRootElement;
023import javax.xml.bind.annotation.XmlTransient;
024
025import org.apache.camel.Processor;
026import org.apache.camel.Service;
027import org.apache.camel.processor.WrapProcessor;
028import org.apache.camel.spi.Metadata;
029import org.apache.camel.spi.Policy;
030import org.apache.camel.spi.RouteContext;
031import org.apache.camel.spi.TransactedPolicy;
032import org.apache.camel.util.ObjectHelper;
033
034/**
035 * Defines a policy the route will use
036 *
037 * @version 
038 */
039@Metadata(label = "configuration")
040@XmlRootElement(name = "policy")
041@XmlAccessorType(XmlAccessType.FIELD)
042public class PolicyDefinition extends OutputDefinition<PolicyDefinition> {
043
044    // TODO: Align this code with TransactedDefinition
045
046    @XmlTransient
047    protected Class<? extends Policy> type;
048    @XmlAttribute(required = true)
049    protected String ref;
050    @XmlTransient
051    private Policy policy;
052
053    public PolicyDefinition() {
054    }
055
056    public PolicyDefinition(Policy policy) {
057        this.policy = policy;
058    }
059
060    @Override
061    public String toString() {
062        return "Policy[" + description() + "]";
063    }
064    
065    protected String description() {
066        if (policy != null) {
067            return policy.toString();
068        } else {
069            return "ref:" + ref;
070        }
071    }
072
073    @Override
074    public String getShortName() {
075        // a policy can be a hidden disguise for a transacted definition
076        boolean transacted = type != null && type.isAssignableFrom(TransactedPolicy.class);
077        return transacted ? "transacted" : "policy";
078    }
079
080    @Override
081    public String getLabel() {
082        return getShortName() + "[" + getDescription() + "]";
083    }
084
085    @Override
086    public boolean isAbstract() {
087        // policy should NOT be abstract
088        return false;
089    }
090
091    @Override
092    public boolean isTopLevelOnly() {
093        // a policy is often top-level but you can have it in lower-levels as well
094        return false;
095    }
096
097    @Override
098    public boolean isWrappingEntireOutput() {
099        return true;
100    }
101
102    public String getRef() {
103        return ref;
104    }
105
106    public void setRef(String ref) {
107        this.ref = ref;
108    }
109
110    /**
111     * Sets a policy type that this definition should scope within.
112     * <p/>
113     * Is used for convention over configuration situations where the policy
114     * should be automatic looked up in the registry and it should be based
115     * on this type. For instance a {@link org.apache.camel.spi.TransactedPolicy}
116     * can be set as type for easy transaction configuration.
117     * <p/>
118     * Will by default scope to the wide {@link Policy}
119     *
120     * @param type the policy type
121     */
122    public void setType(Class<? extends Policy> type) {
123        this.type = type;
124    }
125
126    /**
127     * Sets a reference to use for lookup the policy in the registry.
128     *
129     * @param ref the reference
130     * @return the builder
131     */
132    public PolicyDefinition ref(String ref) {
133        setRef(ref);
134        return this;
135    }
136
137    @Override
138    public Processor createProcessor(RouteContext routeContext) throws Exception {
139        Policy policy = resolvePolicy(routeContext);
140        ObjectHelper.notNull(policy, "policy", this);
141
142        // before wrap
143        policy.beforeWrap(routeContext, this);
144
145        // create processor after the before wrap
146        Processor childProcessor = this.createChildProcessor(routeContext, true);
147
148        // wrap
149        Processor target = policy.wrap(routeContext, childProcessor);
150
151        if (!(target instanceof Service)) {
152            // wrap the target so it becomes a service and we can manage its lifecycle
153            target = new WrapProcessor(target, childProcessor);
154        }
155        return target;
156    }
157
158    protected Policy resolvePolicy(RouteContext routeContext) {
159        if (policy != null) {
160            return policy;
161        }
162        // reuse code on transacted definition to do the resolution
163        return TransactedDefinition.doResolvePolicy(routeContext, getRef(), type);
164    }
165
166}