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