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     */
017    package org.apache.servicemix.eip;
018    
019    import java.net.URL;
020    import java.util.Set;
021    
022    import javax.activation.DataHandler;
023    import javax.jbi.JBIException;
024    import javax.jbi.messaging.ExchangeStatus;
025    import javax.jbi.messaging.MessageExchange;
026    import javax.jbi.messaging.MessagingException;
027    import javax.jbi.messaging.MessageExchange.Role;
028    import javax.jbi.messaging.NormalizedMessage;
029    import javax.jbi.servicedesc.ServiceEndpoint;
030    import javax.wsdl.Definition;
031    import javax.wsdl.WSDLException;
032    import javax.wsdl.factory.WSDLFactory;
033    import javax.wsdl.xml.WSDLReader;
034    
035    import org.apache.servicemix.common.JbiConstants;
036    import org.apache.servicemix.common.endpoints.ProviderEndpoint;
037    import org.apache.servicemix.common.locks.LockManager;
038    import org.apache.servicemix.common.locks.impl.SimpleLockManager;
039    import org.apache.servicemix.eip.support.ExchangeTarget;
040    import org.apache.servicemix.jbi.marshaler.PojoMarshaler;
041    import org.apache.servicemix.store.Store;
042    import org.apache.servicemix.store.StoreFactory;
043    import org.apache.servicemix.store.memory.MemoryStoreFactory;
044    import org.apache.servicemix.timers.TimerManager;
045    import org.apache.servicemix.timers.impl.TimerManagerImpl;
046    import org.springframework.core.io.Resource;
047    import org.w3c.dom.Document;
048    
049    import com.ibm.wsdl.Constants;
050    
051    /**
052     * @author gnodet
053     * @version $Revision: 376451 $
054     */
055    public abstract class EIPEndpoint extends ProviderEndpoint {
056    
057        /**
058         * The resource pointing to the WSDL for this endpoint
059         */
060        protected Resource wsdlResource;
061        
062        /**
063         * The store to keep pending exchanges
064         */
065        protected Store store;
066        /**
067         * The store factory.
068         */
069        protected StoreFactory storeFactory;
070        /**
071         * The lock manager.
072         */
073        protected LockManager lockManager;
074        /**
075         * The timer manager.
076         */
077        protected TimerManager timerManager;
078        
079        /**
080         * The ExchangeTarget to use to get the WSDL
081         */
082        protected ExchangeTarget wsdlExchangeTarget;
083        
084        /**
085         * @return Returns the store.
086         */
087        public Store getStore() {
088            return store;
089        }
090        /**
091         * @param store The store to set.
092         */
093        public void setStore(Store store) {
094            this.store = store;
095        }
096        /**
097         * @return Returns the storeFactory.
098         */
099        public StoreFactory getStoreFactory() {
100            return storeFactory;
101        }
102        /**
103         * @param storeFactory The storeFactory to set.
104         */
105        public void setStoreFactory(StoreFactory storeFactory) {
106            this.storeFactory = storeFactory;
107        }
108        /**
109         * @return the lockManager
110         */
111        public LockManager getLockManager() {
112            return lockManager;
113        }
114        /**
115         * @param lockManager the lockManager to set
116         */
117        public void setLockManager(LockManager lockManager) {
118            this.lockManager = lockManager;
119        }
120        /**
121         * @return the timerManager
122         */
123        public TimerManager getTimerManager() {
124            return timerManager;
125        }
126        /**
127         * @param timerManager the timerManager to set
128         */
129        public void setTimerManager(TimerManager timerManager) {
130            this.timerManager = timerManager;
131        }
132    
133        public void start() throws Exception {
134            super.start();
135            if (store == null) {
136                if (storeFactory == null) {
137                    storeFactory = new MemoryStoreFactory();
138                }
139                store = storeFactory.open(getService().toString() + getEndpoint());
140            }
141            if (lockManager == null) {
142                lockManager = new SimpleLockManager();
143            }
144            if (timerManager == null) {
145                timerManager = new TimerManagerImpl();
146            }
147            timerManager.start();
148        }
149        
150        public void stop() throws Exception {
151            if (timerManager != null) {
152                timerManager.stop();
153            }
154            super.stop();
155        }
156    
157        /* (non-Javadoc)
158         * @see org.apache.servicemix.common.ExchangeProcessor#process(javax.jbi.messaging.MessageExchange)
159         */
160        public void process(MessageExchange exchange) throws Exception {
161            boolean txSync = exchange.isTransacted() && Boolean.TRUE.equals(exchange.getProperty(JbiConstants.SEND_SYNC));
162            if (txSync && exchange.getRole() == Role.PROVIDER && exchange.getStatus() == ExchangeStatus.ACTIVE) {
163                processSync(exchange);
164            } else {
165                processAsync(exchange);
166            }
167        }
168        
169        /**
170         * @return Returns the description.
171         */
172        public Document getDescription() {
173            if (description == null) {
174                definition = getDefinition();
175                if (definition != null) {
176                    try {
177                        description = WSDLFactory.newInstance().newWSDLWriter().getDocument(definition);
178                    } catch (WSDLException e) {
179                        // Ignore
180                    }
181                }
182            }
183            return description;
184        }
185        
186        /**
187         * If the definition is not currently set, it tries to set it using 
188         * the following sources in the order:
189         * description, wsdlResource, wsdlExchangeTarget
190         * 
191         * @return Returns the definition.
192         */
193        public Definition getDefinition() {
194            if (definition == null) {
195                definition = getDefinitionFromDescription();
196                if (definition == null) {
197                    definition = getDefinitionFromWsdlResource();
198                    if (definition == null) {
199                        definition = getDefinitionFromWsdlExchangeTarget();
200                    }
201                }
202            }
203            return definition;
204        }
205        
206        protected Definition getDefinitionFromDescription() {
207            if (description != null) {
208                try {
209                    WSDLReader reader = WSDLFactory.newInstance().newWSDLReader(); 
210                    reader.setFeature(Constants.FEATURE_VERBOSE, false);
211                    return reader.readWSDL(null, description);
212                } catch (WSDLException ignore) {
213                    // Ignore
214                }
215            }
216            return null;
217        }
218    
219        protected Definition getDefinitionFromWsdlResource() {
220            if (wsdlResource != null) {
221                try {
222                    URL resource = wsdlResource.getURL();
223                    WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
224                    reader.setFeature(Constants.FEATURE_VERBOSE, false);
225                    return reader.readWSDL(null, resource.toString());
226                } catch (Throwable ignore) {
227                    // Ignore
228                }
229            }
230            return null;
231        }
232            
233        protected Definition getDefinitionFromWsdlExchangeTarget() {
234            if (wsdlExchangeTarget != null) {
235                try {
236                    Document description = getDescriptionForExchangeTarget(wsdlExchangeTarget);
237                    WSDLReader reader = WSDLFactory.newInstance().newWSDLReader(); 
238                    reader.setFeature(Constants.FEATURE_VERBOSE, false);
239                    return reader.readWSDL(null, description);
240                } catch (Throwable ignore) {
241                    // Ignore
242                }
243            }
244            return null;
245        }
246        
247        /**
248         * @return Returns the wsdl's Resource.
249         */
250        public Resource getWsdlResource() {
251            return wsdlResource;
252        }
253        public void setWsdlResource(Resource wsdlResource) {
254            this.wsdlResource = wsdlResource;
255        }
256        
257        protected Document getDescriptionForExchangeTarget(ExchangeTarget match) throws JBIException {
258            ServiceEndpoint[] endpoints = getEndpointsForExchangeTarget(match);
259            if (endpoints == null || endpoints.length == 0) {
260                return null;
261            }
262            ServiceEndpoint endpoint = chooseFirstEndpointWithDescriptor(endpoints);
263            if (endpoint == null) {
264                return null;
265            }
266            return getContext().getEndpointDescriptor(endpoint);
267        }
268        
269        /**
270         * 
271         * @param match
272         * @return an ServiceEndpoint[] of all the endpoints that matched.
273         * @throws JBIException
274         */
275        protected ServiceEndpoint[] getEndpointsForExchangeTarget(ExchangeTarget match) throws JBIException {
276            ServiceEndpoint[] endpoints;
277            if (match.getEndpoint() != null && match.getService() != null) {
278                ServiceEndpoint endpoint = getContext().getEndpoint(match.getService(), match.getEndpoint());
279                if (endpoint == null) {
280                    endpoints = new ServiceEndpoint[0];
281                } else {
282                    endpoints = new ServiceEndpoint[] {endpoint };
283                }
284            } else if (match.getService() != null) {
285                endpoints = getContext().getEndpointsForService(match.getService());
286            } else if (interfaceName != null) {
287                endpoints = getContext().getEndpoints(interfaceName);
288            } else {
289                throw new IllegalStateException("One of interfaceName or serviceName should be provided");
290            }
291            return endpoints;
292        }
293        
294        protected ServiceEndpoint chooseFirstEndpointWithDescriptor(ServiceEndpoint[] endpoints) throws JBIException {
295            for (int i = 0; i < endpoints.length; i++) {
296                if (getContext().getEndpointDescriptor(endpoints[i]) != null) {
297                    return endpoints[i];
298                }
299            }
300            return null;
301        }
302    
303    
304        protected abstract void processAsync(MessageExchange exchange) throws Exception;
305    
306        protected abstract void processSync(MessageExchange exchange) throws Exception;
307        
308        public ExchangeTarget getWsdlExchangeTarget() {
309            return wsdlExchangeTarget;
310        }
311        public void setWsdlExchangeTarget(ExchangeTarget wsdlExchangeTarget) {
312            this.wsdlExchangeTarget = wsdlExchangeTarget;
313        }
314    
315        /**
316         * Copies properties from one message to another that do not already exist
317         *
318         * @param from the message containing the properties
319         * @param to the destination message where the properties are set
320         */
321        protected void copyProperties(NormalizedMessage from, NormalizedMessage to) {
322            for (String propertyName : (Set<String>) from.getPropertyNames()) {
323                // Do not copy existing properties or transient properties
324                if (to.getProperty(propertyName) == null && !PojoMarshaler.BODY.equals(propertyName)) {
325                    Object value = from.getProperty(propertyName);
326                    to.setProperty(propertyName, value);
327                }
328            }
329        }
330    
331        /**
332         * Copies attachments from one message to another that do not already exist
333         *
334         * @param from the message with the attachments
335         * @param to the destination message where the attachments are to be added
336         * @throws javax.jbi.messaging.MessagingException if an attachment could not be added
337         */
338        protected void copyAttachments(NormalizedMessage from, NormalizedMessage to) throws MessagingException {
339            for (String attachmentName : (Set<String>) from.getAttachmentNames()) {
340                // Do not copy existing attachments
341                if (to.getAttachment(attachmentName) == null) {
342                    DataHandler value = from.getAttachment(attachmentName);
343                    to.addAttachment(attachmentName, value);
344                }
345            }
346        }
347    }