/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.ws.eventing.backend.notification; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.jws.WebService; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.namespace.QName; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.ext.logging.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.apache.cxf.ws.eventing.EventType; import org.apache.cxf.ws.eventing.backend.database.SubscriptionTicket; import org.apache.cxf.ws.eventing.shared.handlers.ReferenceParametersAddingHandler; /** * Represents the task to send a notification about a particular event to a particular subscribed client. * Dispatch is performed according to a provided endpoint interface. */ class EventSinkInterfaceNotificationTask implements Runnable { protected static final Logger LOG = LogUtils.getLogger(EventSinkInterfaceNotificationTask.class); SubscriptionTicket target; Object event; Class<?> endpointInterface; EventSinkInterfaceNotificationTask(SubscriptionTicket ticket, Object event, Class<?> endpointInterface) { this.target = ticket; this.event = event; this.endpointInterface = endpointInterface; } /** * Logic needed to actually send the notification to the subscribed client. */ @Override public void run() { try { LOG.info("Starting notification task for subscription UUID " + target.getUuid()); Method method = null; final Object proxy; final Object param; final Class<?> eventClass = event.getClass(); final Class<?>[] eventClassArray = new Class<?>[] {eventClass}; if (target.isWrappedDelivery()) { proxy = getProxy(WrappedSink.class, eventClassArray); param = new EventType(); ((EventType)param).getContent().add(eventClass.isAnnotationPresent(XmlRootElement.class) ? event : convertToJAXBElement(event)); method = WrappedSink.class.getMethod("notifyEvent", EventType.class); } else { proxy = getProxy(endpointInterface); // find the method to use Method[] methods = endpointInterface.getMethods(); for (int i = 0; i < methods.length && method == null; i++) { if (Arrays.equals(methods[i].getParameterTypes(), eventClassArray)) { method = methods[i]; } } if (method == null) { LOG.severe("Couldn't find corresponding method for event of type " + eventClass.getCanonicalName() + " in event sink interface" + endpointInterface.getCanonicalName()); return; } param = event; } method.invoke(proxy, param); } catch (Throwable e) { e.printStackTrace(); } } @SuppressWarnings({ "unchecked", "rawtypes" }) protected JAXBElement<?> convertToJAXBElement(Object evt) { final Class<?> eventClass = evt.getClass(); String tns = endpointInterface.getAnnotation(WebService.class).targetNamespace(); return new JAXBElement(new QName(tns, eventClass.getName()), eventClass, evt); } protected Object getProxy(Class<?> sinkInterface, Class<?>... extraClasses) { //needed SOAP handlers ReferenceParametersAddingHandler handler = new ReferenceParametersAddingHandler( target.getNotificationReferenceParams()); JaxWsProxyFactoryBean service = new JaxWsProxyFactoryBean(); service.getOutInterceptors().add(new LoggingOutInterceptor()); service.setServiceClass(sinkInterface); service.setAddress(target.getTargetURL()); service.getHandlers().add(handler); // do we need to apply a filter? if (target.getFilter() != null && target.getFilter().getContent().size() > 0) { service.getOutInterceptors().add(new FilteringInterceptor(target.getFilter())); } if (extraClasses != null && extraClasses.length > 0) { Map<String, Object> props = new HashMap<>(); props.put("jaxb.additionalContextClasses", extraClasses); service.getClientFactoryBean().getServiceFactory().setProperties(props); } return service.create(); } }