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.wsn.component;
018    
019    import java.io.StringWriter;
020    import java.lang.reflect.InvocationTargetException;
021    import java.lang.reflect.Method;
022    import java.util.ArrayList;
023    import java.util.Arrays;
024    import java.util.List;
025    
026    import javax.jbi.messaging.ExchangeStatus;
027    import javax.jbi.messaging.Fault;
028    import javax.jbi.messaging.InOnly;
029    import javax.jbi.messaging.MessageExchange;
030    import javax.jbi.messaging.NormalizedMessage;
031    import javax.jws.Oneway;
032    import javax.jws.WebMethod;
033    import javax.jws.WebService;
034    import javax.xml.bind.JAXBContext;
035    import javax.xml.bind.JAXBException;
036    import javax.xml.bind.annotation.XmlRootElement;
037    import javax.xml.namespace.QName;
038    import javax.xml.ws.WebFault;
039    
040    import org.apache.servicemix.common.ExchangeProcessor;
041    import org.apache.servicemix.common.endpoints.ProviderEndpoint;
042    import org.apache.servicemix.jbi.jaxp.StringSource;
043    import org.apache.servicemix.jbi.resolver.URIResolver;
044    import org.apache.servicemix.wsn.ComponentContextAware;
045    import org.oasis_open.docs.wsrf.bf_2.BaseFaultType;
046    
047    public class WSNEndpoint extends ProviderEndpoint implements ExchangeProcessor {
048    
049        protected String address;
050    
051        protected Object pojo;
052    
053        protected JAXBContext jaxbContext;
054    
055        protected Class endpointInterface;
056    
057        public WSNEndpoint(String address, Object pojo) {
058            this.address = address;
059            this.pojo = pojo;
060            String[] parts = URIResolver.split3(address);
061            service = new QName(parts[0], parts[1]);
062            endpoint = parts[2];
063        }
064    
065        @Override
066        public void start() throws Exception {
067            if (pojo instanceof ComponentContextAware) {
068                ((ComponentContextAware) pojo).setContext(getContext());
069            }
070            logger = this.serviceUnit.getComponent().getLogger();
071            WebService ws = getWebServiceAnnotation(pojo.getClass());
072            if (ws == null) {
073                throw new IllegalStateException("Unable to find WebService annotation");
074            }
075            endpointInterface = Class.forName(ws.endpointInterface());
076            jaxbContext = createJAXBContext(endpointInterface);
077            ws = getWebServiceAnnotation(endpointInterface);
078            if (ws != null) {
079                interfaceName = new QName(ws.targetNamespace(), ws.name());
080            }
081            super.start();
082        }
083    
084        public static JAXBContext createJAXBContext(Class interfaceClass) throws JAXBException {
085            List<Class> classes = new ArrayList<Class>();
086            classes.add(JbiFault.class);
087            for (Method mth : interfaceClass.getMethods()) {
088                WebMethod wm = (WebMethod) mth.getAnnotation(WebMethod.class);
089                if (wm != null) {
090                    classes.add(mth.getReturnType());
091                    classes.addAll(Arrays.asList(mth.getParameterTypes()));
092                }
093            }
094            return JAXBContext.newInstance(classes.toArray(new Class[classes.size()]));
095        }
096    
097        @SuppressWarnings("unchecked")
098        public void process(MessageExchange exchange) throws Exception {
099            if (exchange.getStatus() == ExchangeStatus.DONE) {
100                return;
101            } else if (exchange.getStatus() == ExchangeStatus.ERROR) {
102                return;
103            }
104            Object input = jaxbContext.createUnmarshaller().unmarshal(exchange.getMessage("in").getContent());
105            Method webMethod = null;
106            for (Method mth : endpointInterface.getMethods()) {
107                Class[] params = mth.getParameterTypes();
108                if (params.length == 1 && params[0].isAssignableFrom(input.getClass())) {
109                    webMethod = mth;
110                    break;
111                }
112            }
113            if (webMethod == null) {
114                throw new IllegalStateException("Could not determine invoked web method");
115            }
116            boolean oneWay = webMethod.getAnnotation(Oneway.class) != null;
117            Object output;
118            try {
119                output = webMethod.invoke(pojo, new Object[] {input });
120            } catch (InvocationTargetException e) {
121                if (e.getCause() instanceof Exception) {
122                    WebFault fa = (WebFault) e.getCause().getClass().getAnnotation(WebFault.class);
123                    if (!(exchange instanceof InOnly) && fa != null) {
124                        BaseFaultType info = (BaseFaultType) e.getCause().getClass().getMethod("getFaultInfo").invoke(
125                                e.getCause());
126                        Fault fault = exchange.createFault();
127                        exchange.setFault(fault);
128                        exchange.setError((Exception) e.getCause());
129                        StringWriter writer = new StringWriter();
130                        jaxbContext.createMarshaller().marshal(new JbiFault(info), writer);
131                        fault.setContent(new StringSource(writer.toString()));
132                        send(exchange);
133                        return;
134                    } else {
135                        throw (Exception) e.getCause();
136                    }
137                } else if (e.getCause() instanceof Error) {
138                    throw (Error) e.getCause();
139                } else {
140                    throw new RuntimeException(e.getCause());
141                }
142            }
143            if (oneWay) {
144                exchange.setStatus(ExchangeStatus.DONE);
145                send(exchange);
146            } else {
147                NormalizedMessage msg = exchange.createMessage();
148                exchange.setMessage(msg, "out");
149                StringWriter writer = new StringWriter();
150                jaxbContext.createMarshaller().marshal(output, writer);
151                msg.setContent(new StringSource(writer.toString()));
152                send(exchange);
153            }
154        }
155    
156        @XmlRootElement(name = "Fault")
157        public static class JbiFault {
158            private BaseFaultType info;
159    
160            public JbiFault() {
161            }
162    
163            public JbiFault(BaseFaultType info) {
164                this.info = info;
165            }
166    
167            public BaseFaultType getInfo() {
168                return info;
169            }
170    
171            public void setInfo(BaseFaultType info) {
172                this.info = info;
173            }
174        }
175    
176        protected Method getWebServiceMethod(QName interfaceName, QName operation) throws Exception {
177            WebService ws = getWebServiceAnnotation(pojo.getClass());
178            if (ws == null) {
179                throw new IllegalStateException("Unable to find WebService annotation");
180            }
181            Class itf = Class.forName(ws.endpointInterface());
182            for (Method mth : itf.getMethods()) {
183                WebMethod wm = (WebMethod) mth.getAnnotation(WebMethod.class);
184                if (wm != null) {
185                    // TODO: get name ?
186                }
187            }
188            return null;
189        }
190    
191        @SuppressWarnings("unchecked")
192        protected WebService getWebServiceAnnotation(Class clazz) {
193            for (Class cl = clazz; cl != null; cl = cl.getSuperclass()) {
194                WebService ws = (WebService) cl.getAnnotation(WebService.class);
195                if (ws != null) {
196                    return ws;
197                }
198            }
199            return null;
200        }
201    
202    }