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    // TODO: Camel 3 should be NoOutputDefinition
046
047    @XmlTransient
048    protected Class<? extends Policy> type;
049    @XmlAttribute(required = true)
050    protected String ref;
051    @XmlTransient
052    private Policy policy;
053
054    public PolicyDefinition() {
055    }
056
057    public PolicyDefinition(Policy policy) {
058        this.policy = policy;
059    }
060
061    @Override
062    public String toString() {
063        return "Policy[" + description() + "]";
064    }
065    
066    protected String description() {
067        if (policy != null) {
068            return policy.toString();
069        } else {
070            return "ref:" + ref;
071        }
072    }
073
074    @Override
075    public String getShortName() {
076        // a policy can be a hidden disguise for a transacted definition
077        boolean transacted = type != null && type.isAssignableFrom(TransactedPolicy.class);
078        return transacted ? "transacted" : "policy";
079    }
080
081    @Override
082    public String getLabel() {
083        return getShortName() + "[" + getDescription() + "]";
084    }
085
086    @Override
087    public boolean isAbstract() {
088        // policy should NOT be abstract
089        return false;
090    }
091
092    @Override
093    public boolean isTopLevelOnly() {
094        // a policy is often top-level but you can have it in lower-levels as well
095        return false;
096    }
097
098    @Override
099    public boolean isWrappingEntireOutput() {
100        return true;
101    }
102
103    public String getRef() {
104        return ref;
105    }
106
107    public void setRef(String ref) {
108        this.ref = ref;
109    }
110
111    /**
112     * Sets a policy type that this definition should scope within.
113     * <p/>
114     * Is used for convention over configuration situations where the policy
115     * should be automatic looked up in the registry and it should be based
116     * on this type. For instance a {@link org.apache.camel.spi.TransactedPolicy}
117     * can be set as type for easy transaction configuration.
118     * <p/>
119     * Will by default scope to the wide {@link Policy}
120     *
121     * @param type the policy type
122     */
123    public void setType(Class<? extends Policy> type) {
124        this.type = type;
125    }
126
127    /**
128     * Sets a reference to use for lookup the policy in the registry.
129     *
130     * @param ref the reference
131     * @return the builder
132     */
133    public PolicyDefinition ref(String ref) {
134        setRef(ref);
135        return this;
136    }
137
138    @Override
139    public Processor createProcessor(RouteContext routeContext) throws Exception {
140        Policy policy = resolvePolicy(routeContext);
141        ObjectHelper.notNull(policy, "policy", this);
142
143        // before wrap
144        policy.beforeWrap(routeContext, this);
145
146        // create processor after the before wrap
147        Processor childProcessor = this.createChildProcessor(routeContext, true);
148
149        // wrap
150        Processor target = policy.wrap(routeContext, childProcessor);
151
152        if (!(target instanceof Service)) {
153            // wrap the target so it becomes a service and we can manage its lifecycle
154            target = new WrapProcessor(target, childProcessor);
155        }
156        return target;
157    }
158
159    protected Policy resolvePolicy(RouteContext routeContext) {
160        if (policy != null) {
161            return policy;
162        }
163        // reuse code on transacted definition to do the resolution
164        return TransactedDefinition.doResolvePolicy(routeContext, getRef(), type);
165    }
166
167}