View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.config.spring.parsers.specific.endpoint.support;
8   
9   import org.mule.api.config.MuleProperties;
10  import org.mule.config.spring.parsers.AbstractMuleBeanDefinitionParser;
11  import org.mule.config.spring.parsers.MuleChildDefinitionParser;
12  import org.mule.config.spring.parsers.MuleDefinitionParser;
13  import org.mule.config.spring.parsers.delegate.AbstractSingleParentFamilyDefinitionParser;
14  import org.mule.config.spring.parsers.generic.AttributePropertiesDefinitionParser;
15  import org.mule.config.spring.parsers.processors.BlockAttribute;
16  import org.mule.config.spring.parsers.processors.CheckExclusiveAttributes;
17  import org.mule.config.spring.parsers.processors.CheckRequiredAttributes;
18  import org.mule.endpoint.AbstractEndpointBuilder;
19  import org.mule.endpoint.URIBuilder;
20  
21  /**
22   * Combine a
23   * {@link org.mule.config.spring.parsers.specific.endpoint.support.ChildAddressDefinitionParser} and
24   * either a
25   * {@link org.mule.config.spring.parsers.specific.endpoint.support.OrphanEndpointDefinitionParser}
26   * or a
27   * {@link org.mule.config.spring.parsers.specific.endpoint.support.ChildEndpointDefinitionParser}
28   * in one parser.  This lets us put the address attributes in the endpoint element.
29   */
30  public class AddressedEndpointDefinitionParser extends AbstractSingleParentFamilyDefinitionParser
31  {
32      public static final boolean META = ChildAddressDefinitionParser.META;
33      public static final boolean PROTOCOL = ChildAddressDefinitionParser.PROTOCOL;
34      public static final String PROPERTIES = "properties";
35      public static final String[] RESTRICTED_ENDPOINT_ATTRIBUTES =
36              new String[]{MuleProperties.EXCHANGE_PATTERN,
37                      AbstractEndpointBuilder.PROPERTY_RESPONSE_TIMEOUT, "encoding",
38                      "connector", "createConnector", "transformer", "responseTransformer", "disableTransportTransformer", "mimeType"};
39  
40      // this is an example of parsing a single element with several parsers.  in this case
41      // (because we extend AbstractSingleParentFamilyDefinitionParser) the first parser is expected to
42      // create the "parent".  then subsequent parsers will be called as children.
43  
44      // because all are generated from one element we need to be careful to block attributes
45      // that are irrelevant to a particular parser.
46  
47      public AddressedEndpointDefinitionParser(String protocol, MuleDefinitionParser endpointParser)
48      {
49          this(protocol, PROTOCOL, endpointParser);
50      }
51  
52      public AddressedEndpointDefinitionParser(String metaOrProtocol, boolean isMeta, MuleDefinitionParser endpointParser)
53      {
54          this(metaOrProtocol, isMeta, endpointParser, new String[]{}, new String[]{});
55      }
56  
57      public AddressedEndpointDefinitionParser(String metaOrProtocol, boolean isMeta,
58                                               MuleDefinitionParser endpointParser,
59                                               String[] requiredAddressAttributes,
60                                               String[] requiredProperties)
61      {
62          this(metaOrProtocol, isMeta, endpointParser,
63                  RESTRICTED_ENDPOINT_ATTRIBUTES, URIBuilder.ALL_ATTRIBUTES,
64                  new String[][]{requiredAddressAttributes}, new String[][]{requiredProperties});
65      }
66  
67      /**
68       * @param metaOrProtocol The transport metaOrProtocol ("tcp" etc)
69       * @param isMeta Whether transport is "meta" or not (eg cxf)
70       * @param endpointParser The parser for the endpoint
71       * @param endpointAttributes A list of attribute names which will be set as properties on the
72       * endpoint builder
73       * @param addressAttributes A list of attribute names which will be set as properties on the
74       * endpoint URI builder
75       * @param requiredAddressAttributes A list of attribute names that are required if "address"
76       * isn't present
77       * @param requiredProperties A list of property names that are required if "address" isn't present
78       */
79      public AddressedEndpointDefinitionParser(String metaOrProtocol, boolean isMeta,
80                                               MuleDefinitionParser endpointParser,
81                                               String[] endpointAttributes,
82                                               String[] addressAttributes,
83                                               String[][] requiredAddressAttributes,
84                                               String[][] requiredProperties)
85      {
86          // the first delegate, the parent, is an endpoint; we block everything except the endpoint attributes
87          enableAttributes(endpointParser, endpointAttributes);
88          enableAttribute(endpointParser, AbstractMuleBeanDefinitionParser.ATTRIBUTE_NAME);
89          addDelegate(endpointParser);
90  
91          // we handle the address and properties separately, setting the
92          // properties directly on the endpoint (rather than as part of the address)
93          MuleChildDefinitionParser addressParser =
94                  new AddressParser(metaOrProtocol, isMeta, addressAttributes, requiredAddressAttributes);
95  
96          // this handles the exception thrown if a ref is found in the address parser
97          addHandledException(BlockAttribute.BlockAttributeException.class);
98          addChildDelegate(addressParser);
99  
100         MuleChildDefinitionParser propertiesParser =
101                 new PropertiesParser(PROPERTIES, endpointAttributes, requiredAddressAttributes, requiredProperties);
102         addChildDelegate(propertiesParser);
103     }
104 
105     private static class AddressParser extends ChildAddressDefinitionParser
106     {
107 
108         public AddressParser(String metaOrProtocol, boolean isMeta,
109                              String[] addressAttributes, String[][] requiredAddressAttributes)
110         {
111             super(metaOrProtocol, isMeta);
112 
113             // this handles the "ref problem" - we don't want this parsers to be used if a "ref"
114             // defines the address so add a preprocessor to check for that and indicate that the
115             // exception should be handled internally, rather than shown to the user.
116             // we do this before the extra processors below so that this is called last,
117             // allowing other processors to check for conflicts between ref and other attributes
118             registerPreProcessor(new BlockAttribute(AbstractMuleBeanDefinitionParser.ATTRIBUTE_REF));
119 
120             // the address parser sees only the endpoint attributes
121             enableAttributes(this, addressAttributes);
122 
123             // we require either a reference, an address, or the attributes specified
124             // (properties can be used in parallel with "address")
125             String[][] addressAttributeSets =
126             new String[(null != requiredAddressAttributes ? requiredAddressAttributes.length : 0) + 2][];
127             addressAttributeSets[0] = new String[]{URIBuilder.ADDRESS};
128             addressAttributeSets[1] = new String[]{AbstractMuleBeanDefinitionParser.ATTRIBUTE_REF};
129             if (null != requiredAddressAttributes)
130             {
131                 enableAttributes(this, requiredAddressAttributes);
132                 System.arraycopy(requiredAddressAttributes, 0, addressAttributeSets, 2, requiredAddressAttributes.length);
133             }
134             registerPreProcessor(new CheckRequiredAttributes(addressAttributeSets));
135             // and they must be exclusive
136             registerPreProcessor(new CheckExclusiveAttributes(addressAttributeSets));
137         }
138 
139     }
140 
141     private static class PropertiesParser extends AttributePropertiesDefinitionParser
142     {
143 
144         public PropertiesParser(String setter,
145                 String[] endpointAttributes, String[][] requiredAddressAttributes, String[][] requiredProperties)
146         {
147             super(setter);
148 
149             // the properties parser gets to see everything that the other parsers don't - if you
150             // don't want something, don't enable it in the schema!
151             disableAttributes(this, endpointAttributes);
152             disableAttributes(this, URIBuilder.ALL_ATTRIBUTES);
153             disableAttributes(this, requiredAddressAttributes);
154             disableAttribute(this, AbstractMuleBeanDefinitionParser.ATTRIBUTE_NAME);
155             disableAttribute(this, AbstractMuleBeanDefinitionParser.ATTRIBUTE_REF);
156             if (null != requiredProperties && requiredProperties.length > 0 &&
157                     null != requiredProperties[0] && requiredProperties[0].length > 0)
158             {
159                 // if "ref" is present then we don't complain if required properties are missing, since they
160                 // must have been provided on the global endpoint
161                 String[][] requiredPropertiesSets = new String[requiredProperties.length + 1][];
162                 requiredPropertiesSets[0] = new String[]{AbstractMuleBeanDefinitionParser.ATTRIBUTE_REF};
163                 System.arraycopy(requiredProperties, 0, requiredPropertiesSets, 1, requiredProperties.length);
164                 registerPreProcessor(new CheckRequiredAttributes(requiredPropertiesSets));
165             }
166         }
167 
168     }
169 }