/* * Copyright (c) 2008, 2009, 2011-2013, 2015, 2016 Eike Stepper (Berlin, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eike Stepper - initial API and implementation */ package org.eclipse.net4j; import org.eclipse.net4j.acceptor.IAcceptor; import org.eclipse.net4j.channel.IChannelMultiplexer; import org.eclipse.net4j.connector.IServerConnector; import org.eclipse.net4j.signal.SignalProtocol; import org.eclipse.net4j.signal.wrapping.StreamWrapperInjector; import org.eclipse.net4j.util.container.IElementProcessor; import org.eclipse.net4j.util.container.IManagedContainer; import org.eclipse.net4j.util.io.IStreamWrapper; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.net4j.util.security.INegotiator; import org.eclipse.net4j.util.security.NegotiatorFactory; import org.eclipse.internal.net4j.bundle.OM; import org.eclipse.core.runtime.CoreException; import org.eclipse.spi.net4j.Acceptor; import org.eclipse.spi.net4j.AcceptorFactory; import org.eclipse.spi.net4j.InternalChannelMultiplexer; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Reads an XML config file and creates, wires and starts the configured {@link IAcceptor acceptors}. * * @author Eike Stepper * @since 2.0 */ public class TransportConfigurator { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, TransportConfigurator.class); private IManagedContainer container; public TransportConfigurator(IManagedContainer container) { this.container = container; } public IManagedContainer getContainer() { return container; } public IAcceptor[] configure(File configFile) throws ParserConfigurationException, SAXException, IOException, CoreException { if (TRACER.isEnabled()) { TRACER.trace("Configuring Net4j server from " + configFile.getAbsolutePath()); //$NON-NLS-1$ } List<IAcceptor> acceptors = new ArrayList<IAcceptor>(); Document document = getDocument(configFile); NodeList acceptorConfigs = document.getElementsByTagName("acceptor"); //$NON-NLS-1$ for (int i = 0; i < acceptorConfigs.getLength(); i++) { Element acceptorConfig = (Element)acceptorConfigs.item(i); IAcceptor acceptor = configureAcceptor(acceptorConfig); acceptors.add(acceptor); } NodeList streamWrapperConfigs = document.getElementsByTagName("streamWrapper"); //$NON-NLS-1$ for (int i = 0; i < streamWrapperConfigs.getLength(); i++) { Element streamWrapperConfig = (Element)streamWrapperConfigs.item(i); if (getLevel(streamWrapperConfig) == 2) { configureStreamWrapper(streamWrapperConfig, null); } } return acceptors.toArray(new IAcceptor[acceptors.size()]); } protected IAcceptor configureAcceptor(Element acceptorConfig) { String type = acceptorConfig.getAttribute("type"); //$NON-NLS-1$ // TODO Make the following dependent on the "type" attribute value String listenAddr = acceptorConfig.getAttribute("listenAddr"); //$NON-NLS-1$ String port = acceptorConfig.getAttribute("port"); //$NON-NLS-1$ String description = (listenAddr == null ? "" : listenAddr) + (port == null ? "" : ":" + port); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ Acceptor acceptor = (Acceptor)container.getElement(AcceptorFactory.PRODUCT_GROUP, type, description, false); NodeList negotiatorConfigs = acceptorConfig.getElementsByTagName("negotiator"); //$NON-NLS-1$ if (negotiatorConfigs.getLength() > 1) { throw new IllegalStateException("A maximum of one negotiator can be configured for acceptor " + acceptor); //$NON-NLS-1$ } if (negotiatorConfigs.getLength() == 1) { Element negotiatorConfig = (Element)negotiatorConfigs.item(0); INegotiator negotiator = configureNegotiator(negotiatorConfig); acceptor.getConfig().setNegotiator(negotiator); } NodeList streamWrapperConfigs = acceptorConfig.getElementsByTagName("streamWrapper"); //$NON-NLS-1$ for (int i = 0; i < streamWrapperConfigs.getLength(); i++) { Element streamWrapperConfig = (Element)streamWrapperConfigs.item(i); if (getLevel(streamWrapperConfig) == 3) { configureStreamWrapper(streamWrapperConfig, acceptor); } } OM.LOG.info("Net4j acceptor starting: " + type + "://" + description); acceptor.activate(); return acceptor; } protected INegotiator configureNegotiator(Element negotiatorConfig) { String type = negotiatorConfig.getAttribute("type"); //$NON-NLS-1$ String description = negotiatorConfig.getAttribute("description"); //$NON-NLS-1$ return (INegotiator)container.getElement(NegotiatorFactory.PRODUCT_GROUP, type, description); } /** * @since 4.5 */ protected void configureStreamWrapper(Element streamWrapperConfig, Acceptor acceptor) { String type = streamWrapperConfig.getAttribute("type");//$NON-NLS-1$ String description = streamWrapperConfig.getAttribute("description"); //$NON-NLS-1$ String protocolName = streamWrapperConfig.getAttribute("protocol");//$NON-NLS-1$ IStreamWrapper streamWrapper = (IStreamWrapper)container.getElement(IStreamWrapper.Factory.PRODUCT_GROUP, type, description); if (streamWrapper != null) { IElementProcessor injector = new AcceptorStreamWrapperInjector(protocolName, acceptor, streamWrapper); container.addPostProcessor(injector); } } protected Document getDocument(File configFile) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(configFile); } protected Element getStoreConfig(Element repositoryConfig) { NodeList storeConfigs = repositoryConfig.getElementsByTagName("store"); //$NON-NLS-1$ if (storeConfigs.getLength() != 1) { String repositoryName = repositoryConfig.getAttribute("name"); //$NON-NLS-1$ throw new IllegalStateException("Exactly one store must be configured for repository " + repositoryName); //$NON-NLS-1$ } return (Element)storeConfigs.item(0); } public static Map<String, String> getProperties(Element element, int levels) { Map<String, String> properties = new HashMap<String, String>(); collectProperties(element, "", properties, levels); //$NON-NLS-1$ return properties; } private static void collectProperties(Element element, String prefix, Map<String, String> properties, int levels) { if ("property".equals(element.getNodeName())) //$NON-NLS-1$ { String name = element.getAttribute("name"); //$NON-NLS-1$ String value = element.getAttribute("value"); //$NON-NLS-1$ properties.put(prefix + name, value); prefix += name + "."; //$NON-NLS-1$ } if (levels > 0) { NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node childNode = childNodes.item(i); if (childNode instanceof Element) { collectProperties((Element)childNode, prefix, properties, levels - 1); } } } } private static int getLevel(Node node) { Node parentNode = node.getParentNode(); return parentNode != null ? getLevel(parentNode) + 1 : 0; } /** * @author Eike Stepper */ private static final class AcceptorStreamWrapperInjector extends StreamWrapperInjector { private final IAcceptor acceptor; public AcceptorStreamWrapperInjector(String protocolID, IAcceptor acceptor, IStreamWrapper streamWrapper) { super(protocolID, streamWrapper); this.acceptor = acceptor; } @Override protected boolean shouldInject(IManagedContainer container, String productGroup, String factoryType, String description, SignalProtocol<?> signalProtocol) { if (super.shouldInject(container, productGroup, factoryType, description, signalProtocol)) { if (acceptor == null) { return true; } IChannelMultiplexer multiplexer = InternalChannelMultiplexer.CONTEXT_MULTIPLEXER.get(); if (multiplexer instanceof IServerConnector) { IServerConnector serverConnector = (IServerConnector)multiplexer; if (serverConnector.getAcceptor() == acceptor) { return true; } } } return false; } } }