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    public String getRef() {
098        return ref;
099    }
100
101    public void setRef(String ref) {
102        this.ref = ref;
103    }
104
105    /**
106     * Sets a policy type that this definition should scope within.
107     * <p/>
108     * Is used for convention over configuration situations where the policy
109     * should be automatic looked up in the registry and it should be based
110     * on this type. For instance a {@link org.apache.camel.spi.TransactedPolicy}
111     * can be set as type for easy transaction configuration.
112     * <p/>
113     * Will by default scope to the wide {@link Policy}
114     *
115     * @param type the policy type
116     */
117    public void setType(Class<? extends Policy> type) {
118        this.type = type;
119    }
120
121    /**
122     * Sets a reference to use for lookup the policy in the registry.
123     *
124     * @param ref the reference
125     * @return the builder
126     */
127    public PolicyDefinition ref(String ref) {
128        setRef(ref);
129        return this;
130    }
131
132    @Override
133    public Processor createProcessor(RouteContext routeContext) throws Exception {
134        Policy policy = resolvePolicy(routeContext);
135        ObjectHelper.notNull(policy, "policy", this);
136
137        // before wrap
138        policy.beforeWrap(routeContext, this);
139
140        // create processor after the before wrap
141        Processor childProcessor = this.createChildProcessor(routeContext, true);
142
143        // wrap
144        Processor target = policy.wrap(routeContext, childProcessor);
145
146        if (!(target instanceof Service)) {
147            // wrap the target so it becomes a service and we can manage its lifecycle
148            target = new WrapProcessor(target, childProcessor);
149        }
150        return target;
151    }
152
153    protected Policy resolvePolicy(RouteContext routeContext) {
154        if (policy != null) {
155            return policy;
156        }
157        // reuse code on transacted definition to do the resolution
158        return TransactedDefinition.doResolvePolicy(routeContext, getRef(), type);
159    }
160
161}