package org.ow2.chameleon.fuchsia.exporter.protobuffer;
/*
* #%L
* OW2 Chameleon - Fuchsia Exporter Protobuffer
* %%
* Copyright (C) 2009 - 2014 OW2 Chameleon
* %%
* Licensed 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.
* #L%
*/
import com.google.code.cxf.protobuf.ProtobufServerFactoryBean;
import com.google.code.cxf.protobuf.binding.ProtobufBindingFactory;
import com.google.protobuf.Service;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.binding.BindingFactoryManager;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.apache.felix.ipojo.annotations.*;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.Container;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.ow2.chameleon.fuchsia.core.FuchsiaUtils;
import org.ow2.chameleon.fuchsia.core.component.AbstractExporterComponent;
import org.ow2.chameleon.fuchsia.core.component.ExporterService;
import org.ow2.chameleon.fuchsia.core.declaration.ExportDeclaration;
import org.ow2.chameleon.fuchsia.core.exceptions.BinderException;
import org.ow2.chameleon.fuchsia.exporter.protobuffer.internal.ProtobufferExportDeclarationWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Component
@Provides(specifications = {ExporterService.class})
public class ProtobufferExporter extends AbstractExporterComponent {
private static final Logger LOG = LoggerFactory.getLogger(ProtobufferExporter.class);
private final BundleContext context;
private Map<String, Server> serverPublished = new HashMap<String, Server>();
private org.eclipse.jetty.server.Server httpServer;
@ServiceProperty(name = "org.osgi.service.http.port")
private Integer httpPort;
private Bus cxfbus;
@Requires
private HttpService http;
@ServiceProperty(name = "target", value = "(&(rpc.export.address=*)(scope=generic))")
private String filter;
public ProtobufferExporter(BundleContext context) {
this.context = context;
}
@Validate
public void start() {
System.setProperty("org.apache.cxf.nofastinfoset", "true");
super.start();
CXFNonSpringServlet cxfServlet = new CXFNonSpringServlet();
if (http != null) {
try {
http.registerServlet("/cxf", cxfServlet, null, null);
} catch (ServletException e) {
LOG.error("Failed registering CXF servlet", e);
} catch (NamespaceException e) {
LOG.error("Failed registering CXF servlet", e);
}
} else {
try {
cxfServlet = configStandaloneServer();
httpServer.start();
} catch (Exception e1) {
LOG.error("Impossible to start standalone CXF Jetty server.", e1);
}
}
cxfbus = cxfServlet.getBus();
}
private CXFServlet configStandaloneServer() {
httpServer = new org.eclipse.jetty.server.Server(httpPort);
Bus bus = BusFactory.getDefaultBus(true);
ContextHandlerCollection contexts = new ContextHandlerCollection();
httpServer.setHandler(contexts);
ServletContextHandler root = new ServletContextHandler(contexts, "/",
ServletContextHandler.SESSIONS);
CXFServlet cxf = new CXFServlet();
cxf.setBus(bus);
ServletHolder servlet = new ServletHolder(cxf);
root.addServlet(servlet, "/cxf/*");
return cxf;
}
@Invalidate
public void stop() {
super.stop();
if (httpServer != null) {
try {
httpServer.stop();
} catch (Exception e) {
LOG.warn("Failed to stop standalone server.", e);
}
}
for (Map.Entry<String, Server> entry : serverPublished.entrySet()) {
serverPublished.remove(entry.getKey());
entry.getValue().stop();
}
}
@Override
protected void useExportDeclaration(ExportDeclaration exportDeclaration) throws BinderException {
LOG.info("initiating exportation...");
ProtobufferExportDeclarationWrapper pojo = ProtobufferExportDeclarationWrapper.create(exportDeclaration);
Class inter;
Class messageClass;
try {
inter = FuchsiaUtils.loadClass(context, String.format("%s$%s", pojo.getClazz(), pojo.getService()));
messageClass = FuchsiaUtils.loadClass(context, String.format("%s$%s", pojo.getClazz(), pojo.getMessage()));
} catch (ClassNotFoundException e) {
LOG.error("Class not found", e);
return;
}
LOG.info("Looking for service that provides class {}", pojo.getClazz() + "$" + pojo.getService());
Collection<ServiceReference<Service>> protobuffReferences = null;
try {
protobuffReferences = context.getServiceReferences(inter, pojo.getFilter());
} catch (InvalidSyntaxException e) {
LOG.error("Invalid filter exception", e);
return;
}
LOG.info("using filter " + pojo.getFilter() + " to find instance");
if (protobuffReferences.isEmpty()) {
LOG.info("nothing to be exported was found");
} else if (protobuffReferences.size() == 1) {
for (ServiceReference<Service> sr : protobuffReferences) {
Service protobufferService = context.getService(sr);
BindingFactoryManager mgr = cxfbus.getExtension(BindingFactoryManager.class);
mgr.registerBindingFactory(ProtobufBindingFactory.PROTOBUF_BINDING_ID, new ProtobufBindingFactory(cxfbus));
ProtobufServerFactoryBean serverFactoryBean = new ProtobufServerFactoryBean();
serverFactoryBean.setAddress(pojo.getAddress());
serverFactoryBean.setBus(cxfbus);
serverFactoryBean.setServiceBean(inter.cast(protobufferService));
serverFactoryBean.setMessageClass(messageClass);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(Container.class.getClassLoader());
Server server = serverFactoryBean.create();
serverPublished.put(pojo.getId(), server);
Thread.currentThread().setContextClassLoader(loader);
LOG.info("exporting the service with the id:" + pojo.getId());
}
} else {
LOG.info("more than one were found to be exported");
}
}
@Override
protected void denyExportDeclaration(ExportDeclaration exportDeclaration) throws BinderException {
ProtobufferExportDeclarationWrapper pojo = ProtobufferExportDeclarationWrapper.create(exportDeclaration);
Server server = serverPublished.get(pojo.getId());
serverPublished.remove(pojo.getId());
if (server != null) {
LOG.info("Destroying endpoint:" + server.getEndpoint().getEndpointInfo().getAddress());
server.destroy();
} else {
LOG.warn("no endpoint to destroy");
}
}
public String getName() {
return this.getClass().getName();
}
}