/**
* 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.transport.http.netty.server;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import org.apache.cxf.Bus;
import org.apache.cxf.buslifecycle.BusLifeCycleListener;
import org.apache.cxf.buslifecycle.BusLifeCycleManager;
import org.apache.cxf.common.injection.NoJSR250Annotations;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
@NoJSR250Annotations(unlessNull = "bus")
public class NettyHttpServerEngineFactory implements BusLifeCycleListener {
private static final Logger LOG =
LogUtils.getL7dLogger(NettyHttpServerEngineFactory.class);
private static ConcurrentHashMap<Integer, NettyHttpServerEngine> portMap =
new ConcurrentHashMap<Integer, NettyHttpServerEngine>();
private Bus bus;
private BusLifeCycleManager lifeCycleManager;
/**
* This map holds the threading parameters that are to be applied
* to new Engines when bound to the reference id.
*/
private Map<String, ThreadingParameters> threadingParametersMap =
new TreeMap<String, ThreadingParameters>();
private Map<String, TLSServerParameters> tlsServerParametersMap =
new TreeMap<String, TLSServerParameters>();
public NettyHttpServerEngineFactory() {
// Empty
}
public NettyHttpServerEngineFactory(Bus b) {
setBus(b);
}
public NettyHttpServerEngineFactory(Bus b,
Map<String, TLSServerParameters> tls,
Map<String, ThreadingParameters> threads) {
setBus(b);
tlsServerParametersMap = tls;
threadingParametersMap = threads;
}
public Bus getBus() {
return bus;
}
/**
* This call is used to set the bus. It should only be called once.
*
* @param bus
*/
@Resource(name = "cxf")
public final void setBus(Bus bus) {
this.bus = bus;
if (bus != null) {
bus.setExtension(this, NettyHttpServerEngineFactory.class);
lifeCycleManager = bus.getExtension(BusLifeCycleManager.class);
if (null != lifeCycleManager) {
lifeCycleManager.registerLifeCycleListener(this);
}
}
}
public Map<String, TLSServerParameters> getTlsServerParametersMap() {
return tlsServerParametersMap;
}
public void setTlsServerParameters(Map<String, TLSServerParameters> tlsParametersMap) {
this.tlsServerParametersMap = tlsParametersMap;
}
public Map<String, ThreadingParameters> getThreadingParametersMap() {
return threadingParametersMap;
}
public void setThreadingParametersMap(Map<String, ThreadingParameters> parameterMap) {
this.threadingParametersMap = parameterMap;
}
public void setEnginesList(List<NettyHttpServerEngine> enginesList) {
for (NettyHttpServerEngine engine : enginesList) {
portMap.putIfAbsent(engine.getPort(), engine);
}
}
public void initComplete() {
// do nothing here
}
public void postShutdown() {
// shut down the Netty server in the portMap
// To avoid the CurrentModificationException,
// do not use portMap.values directly
NettyHttpServerEngine[] engines = portMap.values().toArray(new NettyHttpServerEngine[portMap.values().size()]);
for (NettyHttpServerEngine engine : engines) {
engine.shutdown();
}
// The engine which is in shutdown status cannot be started anymore
portMap.clear();
threadingParametersMap.clear();
tlsServerParametersMap.clear();
}
public void preShutdown() {
// do nothing here
// just let server registry to call the server stop first
}
private static NettyHttpServerEngine getOrCreate(NettyHttpServerEngineFactory factory,
String host,
int port,
TLSServerParameters tlsParams
) throws IOException {
NettyHttpServerEngine ref = portMap.get(port);
if (ref == null) {
ref = new NettyHttpServerEngine(host, port);
if (tlsParams != null) {
ref.setTlsServerParameters(tlsParams);
}
ref.finalizeConfig();
NettyHttpServerEngine tmpRef = portMap.putIfAbsent(port, ref);
if (tmpRef != null) {
ref = tmpRef;
}
}
return ref;
}
public synchronized NettyHttpServerEngine retrieveNettyHttpServerEngine(int port) {
return portMap.get(port);
}
public synchronized NettyHttpServerEngine createNettyHttpServerEngine(String host, int port,
String protocol) throws IOException {
LOG.log(Level.FINE, "CREATING_NETTY_SERVER_ENGINE", port);
TLSServerParameters tlsServerParameters = null;
if ("https".equals(protocol) && tlsServerParametersMap != null) {
tlsServerParameters = tlsServerParametersMap.get(Integer.toString(port));
}
NettyHttpServerEngine ref = getOrCreate(this, host, port, tlsServerParameters);
// checking the protocol
if (!protocol.equals(ref.getProtocol())) {
throw new IOException("Protocol mismatch for port " + port + ": "
+ "engine's protocol is " + ref.getProtocol()
+ ", the url protocol is " + protocol);
}
return ref;
}
public synchronized NettyHttpServerEngine createNettyHttpServerEngine(int port,
String protocol) throws IOException {
return createNettyHttpServerEngine(null, port, protocol);
}
/**
* This method removes the Server Engine from the port map and stops it.
*/
public static synchronized void destroyForPort(int port) {
NettyHttpServerEngine ref = portMap.remove(port);
if (ref != null) {
LOG.log(Level.FINE, "STOPPING_NETTY_SERVER_ENGINE", port);
try {
ref.shutdown();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}