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