/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://opensource.org/licenses/cddl1.php
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://opensource.org/licenses/cddl1.php.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
* Portions Copyrighted 2010-2014 ForgeRock AS.
*/
package org.identityconnectors.framework.server.impl;
import java.net.ServerSocket;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import org.identityconnectors.framework.api.ConnectorFacadeFactory;
import org.identityconnectors.framework.api.ConnectorInfoManagerFactory;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.impl.api.ConnectorInfoManagerFactoryImpl;
import org.identityconnectors.framework.impl.api.ManagedConnectorFacadeFactoryImpl;
import org.identityconnectors.framework.server.ConnectorServer;
public class ConnectorServerImpl extends ConnectorServer {
private ConnectionListener listener;
private CountDownLatch stopLatch;
private Timer timer = null;
private Long startDate = null;
@Override
public Long getStartTime() {
return startDate;
}
@Override
public boolean isStarted() {
return listener != null;
}
@Override
public void start() {
if (isStarted()) {
throw new IllegalStateException("Server is already running.");
}
if (getPort() == 0) {
throw new IllegalStateException("Port must be set prior to starting server.");
}
if (getKeyHash() == null) {
throw new IllegalStateException("Key hash must be set prior to starting server.");
}
// make sure we are configured properly
final ConnectorInfoManagerFactoryImpl factory =
(ConnectorInfoManagerFactoryImpl) ConnectorInfoManagerFactory.getInstance();
factory.getLocalManager(getBundleURLs(), getBundleParentClassLoader());
final ServerSocket socket = createServerSocket();
final ConnectionListener listener = new ConnectionListener(this, socket);
listener.setDaemon(true);
listener.start();
stopLatch = new CountDownLatch(1);
startDate = System.currentTimeMillis();
this.listener = listener;
// Create an inferred delegate that invokes methods for the timer.
if (getMaxFacadeLifeTime() > 0) {
FacadeDisposer statusChecker =
new FacadeDisposer(getMaxFacadeLifeTime() * 60, TimeUnit.SECONDS);
timer = new Timer();
timer.scheduleAtFixedRate(statusChecker, new Date(), TimeUnit.SECONDS.toMillis(Math
.min(getMaxFacadeLifeTime() * 60, 600)));
}
}
private ServerSocket createServerSocket() {
try {
ServerSocketFactory factory;
if (getUseSSL()) {
factory = createSSLServerSocketFactory();
} else {
factory = ServerSocketFactory.getDefault();
}
final ServerSocket rv;
if (getIfAddress() == null) {
rv = factory.createServerSocket(getPort(), getMaxConnections());
} else {
rv = factory.createServerSocket(getPort(), getMaxConnections(), getIfAddress());
}
return rv;
} catch (Exception e) {
throw ConnectorException.wrap(e);
}
}
private ServerSocketFactory createSSLServerSocketFactory() throws Exception {
KeyManager[] keyManagers = null;
// convert empty to null
if (getKeyManagers().size() > 0) {
keyManagers = getKeyManagers().toArray(new KeyManager[getKeyManagers().size()]);
}
// the only way to get the default keystore is this way
if (keyManagers == null) {
return SSLServerSocketFactory.getDefault();
} else {
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagers, null, null);
return context.getServerSocketFactory();
}
}
@Override
public void stop() {
if (listener != null) {
try {
listener.shutdown();
} finally {
stopLatch.countDown();
}
stopLatch = null;
startDate = null;
listener = null;
}
if (null != timer) {
timer.cancel();
timer = null;
}
ConnectorFacadeFactory.getManagedInstance().dispose();
}
@Override
public void awaitStop() throws InterruptedException {
stopLatch.await();
}
private class FacadeDisposer extends TimerTask {
private final long delay;
private final TimeUnit unit;
public FacadeDisposer(long time, TimeUnit unit) {
this.delay = time;
this.unit = unit;
}
@Override
public void run() {
logger.ok("Invoking Managed ConnectorFacade Disposer");
ConnectorFacadeFactory factory = ConnectorFacadeFactory.getManagedInstance();
if (factory instanceof ManagedConnectorFacadeFactoryImpl) {
((ManagedConnectorFacadeFactoryImpl) factory).evictIdle(delay, unit);
}
}
}
}