/* * #%L * Service Locator Client for CXF * %% * Copyright (C) 2011 - 2012 Talend Inc. * %% * 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% */ package org.talend.esb.servicelocator.cxf.internal; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.cxf.Bus; import org.apache.cxf.endpoint.Server; import org.apache.cxf.endpoint.ServerLifeCycleListener; import org.apache.cxf.endpoint.ServerLifeCycleManager; import org.apache.cxf.endpoint.ServerRegistry; import org.apache.cxf.service.model.EndpointInfo; import org.apache.cxf.transport.Destination; import org.apache.cxf.ws.policy.EndpointPolicy; import org.apache.cxf.ws.policy.PolicyEngine; import org.apache.neethi.Assertion; import org.apache.neethi.Policy; import org.apache.neethi.PolicyComponent; import org.apache.wss4j.policy.model.AbstractToken; import org.apache.wss4j.policy.model.HttpsToken; import org.apache.wss4j.policy.model.TransportBinding; import org.apache.wss4j.policy.model.TransportToken; import org.talend.esb.servicelocator.client.SLProperties; import org.talend.esb.servicelocator.client.ServiceLocator; import org.talend.esb.servicelocator.client.ServiceLocatorException; import org.talend.esb.servicelocator.client.TransportType; /** * The LocatorRegistrar is responsible for registering the endpoints of CXF Servers at the Service Locator. * The Servers endpoint can either be {@link #registerServer(Server) registered explicitly} or the * LocatorRegistrar can be {@link #startListenForServers() enabled to listen for all Servers} that are in the * process to start and to register them all. * <p/> * If a server which was registered before stops the LocatorRegistrar automatically unregisters from the * Service Locator. */ public class SingleBusLocatorRegistrar implements ServerLifeCycleListener, ServiceLocator.PostConnectAction { private static final Logger LOG = Logger.getLogger(SingleBusLocatorRegistrar.class.getPackage().getName()); private Bus bus; private ServiceLocator locatorClient; private String endpointPrefix = ""; private Map<String, String> endpointPrefixes; private Map<Server, CXFEndpointProvider> registeredServers = Collections.synchronizedMap(new LinkedHashMap<Server, CXFEndpointProvider>()); private boolean listenForServersEnabled; public SingleBusLocatorRegistrar(Bus bus) { this.bus = bus; registerListener(); } @Override public void startServer(Server server) { if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Server " + server + " starting..."); } if (listenForServersEnabled) { registerServer(server); } } @Override public void stopServer(Server server) { if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Server " + server + " stopping..."); } if (registeredServers.containsKey(server)) { unregisterServer(server); } } public void startListenForServers() { check(bus, "bus", "startListenForServers"); listenForServersEnabled = true; registerAvailableServers(); } public void stopListenForServers() { listenForServersEnabled = false; } @Override public void process(ServiceLocator lc) { for (Server server : registeredServers.keySet()) { registerServer(registeredServers.get(server)); } } public void setEndpointPrefix(String endpointPrefix) { this.endpointPrefix = endpointPrefix != null ? endpointPrefix : ""; } public void setEndpointPrefixes(Map<String, String> endpointPrefixes) { this.endpointPrefixes = endpointPrefixes; } public void setServiceLocator(ServiceLocator serviceLocator) { locatorClient = serviceLocator; locatorClient.addPostConnectAction(this); if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Locator client was set."); } } private void registerListener() { ServerLifeCycleManager manager = bus.getExtension(ServerLifeCycleManager.class); if (manager != null) { manager.registerListener(this); if (LOG.isLoggable(Level.FINE)) { LOG.log(Level.FINE, "Server life cycle listener registered."); } } else { if (LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "ServerLifeCycleManager is not available."); } } } public void registerServer(Server server) { registerServer(server, null); } public void registerServer(Server server, SLProperties props) { check(locatorClient, "serviceLocator", "registerEndpoint"); String address = getAddress(server); if (isRelativeAddress(address)) { // relative address String prefix = null; if (endpointPrefixes == null || endpointPrefixes.size() == 0) { prefix = endpointPrefix; } else { if (isSecuredByProperty(server) || isSecuredByPolicy(server)) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("Endpoint " + server.getEndpoint().getEndpointInfo().getService().toString() + " is secured"); } prefix = endpointPrefixes.get(TransportType.HTTPS.toString()); } else { prefix = endpointPrefixes.get(TransportType.HTTP.toString()); } if (prefix == null || prefix.equals("")) { LOG.warning("endpointPrefixes defined but empty. Using default"); prefix = endpointPrefix; } } address = prefix + address; } CXFEndpointProvider endpoint = new CXFEndpointProvider(server, address, props); registerServer(endpoint); registeredServers.put(server, endpoint); } private void registerServer(CXFEndpointProvider endpointProvider) { try { locatorClient.register(endpointProvider); } catch (ServiceLocatorException e) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "ServiceLocator Exception thrown when registering for endpoint " + endpointProvider, e); } } catch (InterruptedException e) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "Interrupted Exception thrown when registering for endpoint " + endpointProvider, e); } } } private void unregisterServer(Server server) { try { CXFEndpointProvider epp = registeredServers.get(server); locatorClient.unregister(epp); } catch (ServiceLocatorException e) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "ServiceLocator Exception thrown during unregister endpoint. ", e); } } catch (InterruptedException e) { if (LOG.isLoggable(Level.SEVERE)) { LOG.log(Level.SEVERE, "Interrupted Exception thrown during unregister endpoint.", e); } } } private void registerAvailableServers() { ServerRegistry serverRegistry = bus.getExtension(ServerRegistry.class); List<Server> servers = serverRegistry.getServers(); for (Server server : servers) { registerServer(server); } } private String getAddress(Server server) { return server.getEndpoint().getEndpointInfo().getAddress(); } private boolean isRelativeAddress(String address) { if (address.startsWith("http://") || address.startsWith("https://")) { return false; } return true; } /** * Is the transport secured by a policy */ private boolean isSecuredByPolicy(Server server) { boolean isSecured = false; EndpointInfo ei = server.getEndpoint().getEndpointInfo(); PolicyEngine pe = bus.getExtension(PolicyEngine.class); if (null == pe) { LOG.finest("No Policy engine found"); return isSecured; } Destination destination = server.getDestination(); EndpointPolicy ep = pe.getServerEndpointPolicy(ei, destination, null); Collection<Assertion> assertions = ep.getChosenAlternative(); for (Assertion a : assertions) { if (a instanceof TransportBinding) { TransportBinding tb = (TransportBinding) a; TransportToken tt = tb.getTransportToken(); AbstractToken t = tt.getToken(); if (t instanceof HttpsToken) { isSecured = true; break; } } } Policy policy = ep.getPolicy(); List<PolicyComponent> pcList = policy.getPolicyComponents(); for (PolicyComponent a : pcList) { if (a instanceof TransportBinding) { TransportBinding tb = (TransportBinding) a; TransportToken tt = tb.getTransportToken(); AbstractToken t = tt.getToken(); if (t instanceof HttpsToken) { isSecured = true; break; } } } return isSecured; } /** * Is the transport secured by a JAX-WS property */ private boolean isSecuredByProperty(Server server) { boolean isSecured = false; Object value = server.getEndpoint().get("org.talend.tesb.endpoint.secured"); //Property name TBD if (value instanceof String) { try { isSecured = Boolean.valueOf((String) value); } catch (Exception ex) { } } return isSecured; } private void check(Object obj, String propertyName, String methodName) { if (obj == null) { throw new IllegalStateException("The property " + propertyName + " must be set before " + methodName + " can be called."); } } }