/*
* #%L
* =====================================================
* _____ _ ____ _ _ _ _
* |_ _|_ __ _ _ ___| |_ / __ \| | | | ___ | | | |
* | | | '__| | | / __| __|/ / _` | |_| |/ __|| |_| |
* | | | | | |_| \__ \ |_| | (_| | _ |\__ \| _ |
* |_| |_| \__,_|___/\__|\ \__,_|_| |_||___/|_| |_|
* \____/
*
* =====================================================
*
* Hochschule Hannover
* (University of Applied Sciences and Arts, Hannover)
* Faculty IV, Dept. of Computer Science
* Ricklinger Stadtweg 118, 30459 Hannover, Germany
*
* Email: trust@f4-i.fh-hannover.de
* Website: http://trust.f4.hs-hannover.de/
*
* This file is part of visitmeta-dataservice, version 0.6.0,
* implemented by the Trust@HsH research group at the Hochschule Hannover.
* %%
* Copyright (C) 2012 - 2016 Trust@HsH
* %%
* 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 de.hshannover.f4.trust.visitmeta.connections;
import org.apache.log4j.Logger;
import de.hshannover.f4.trust.ifmapj.IfmapJ;
import de.hshannover.f4.trust.ifmapj.channel.SSRC;
import de.hshannover.f4.trust.ifmapj.config.BasicAuthConfig;
import de.hshannover.f4.trust.ifmapj.exception.CommunicationException;
import de.hshannover.f4.trust.ifmapj.exception.EndSessionException;
import de.hshannover.f4.trust.ifmapj.exception.IfmapErrorResult;
import de.hshannover.f4.trust.ifmapj.exception.IfmapException;
import de.hshannover.f4.trust.ifmapj.exception.InitializationException;
import de.hshannover.f4.trust.ifmapj.messages.PollResult;
import de.hshannover.f4.trust.ifmapj.messages.SubscribeRequest;
import de.hshannover.f4.trust.visitmeta.data.MapServerDataImpl;
import de.hshannover.f4.trust.visitmeta.dataservice.factories.InMemoryIdentifierFactory;
import de.hshannover.f4.trust.visitmeta.dataservice.factories.InMemoryMetadataFactory;
import de.hshannover.f4.trust.visitmeta.exceptions.ifmap.ConnectionCloseException;
import de.hshannover.f4.trust.visitmeta.exceptions.ifmap.ConnectionEstablishedException;
import de.hshannover.f4.trust.visitmeta.exceptions.ifmap.ConnectionException;
import de.hshannover.f4.trust.visitmeta.exceptions.ifmap.IfmapConnectionException;
import de.hshannover.f4.trust.visitmeta.exceptions.ifmap.NoSavedSubscriptionException;
import de.hshannover.f4.trust.visitmeta.exceptions.ifmap.NotConnectedException;
import de.hshannover.f4.trust.visitmeta.ifmap.SubscriptionHelper;
import de.hshannover.f4.trust.visitmeta.ifmap.SubscriptionImpl;
import de.hshannover.f4.trust.visitmeta.ifmap.UpdateService;
import de.hshannover.f4.trust.visitmeta.interfaces.GraphService;
import de.hshannover.f4.trust.visitmeta.interfaces.Subscription;
import de.hshannover.f4.trust.visitmeta.interfaces.connections.MapServerConnection;
import de.hshannover.f4.trust.visitmeta.interfaces.data.Data;
import de.hshannover.f4.trust.visitmeta.interfaces.data.MapServerData;
import de.hshannover.f4.trust.visitmeta.interfaces.data.SubscriptionData;
import de.hshannover.f4.trust.visitmeta.persistence.neo4j.Neo4JDatabase;
import de.hshannover.f4.trust.visitmeta.util.yaml.ConnectionsProperties;
/**
* Represents an IF-MAP connection to a MAP server. If not changed by
* yourself, following default values are set:
* <ul>
* <li>AuthenticationBasic = true</li>
* <li>TruststorePath = see config.property(ifmap.defaultConnectionSettings.truststorePath)</li>
* <li>TruststorePassword = see config.property(ifmap.defaultConnectionSettings.truststorePassword)</li>
* <li>MaxPollResultSize = see config.property(ifmap.defaultConnectionSettings.maxPollResultSize)</li>
* <li>StartupConnect = see config.property(ifmap.defaultConnectionSettings.useConnectionAsStartup)</li>
* </ul>
*
* @author Marcel Reichenbach
*/
public class MapServerConnectionImpl extends MapServerDataImpl implements MapServerConnection {
private static final Logger LOGGER = Logger.getLogger(MapServerConnectionImpl.class);
private Neo4JDatabase mNeo4JDb;
private UpdateService mUpdateService;
private Thread mUpdateThread;
private SSRC mSsrc;
public MapServerConnectionImpl(String name) {
super(name);
init();
}
public MapServerConnectionImpl(String name, String url, String userName, String userPassword) {
super(name, url, userName, userPassword);
init();
}
public MapServerConnectionImpl(MapServerData connectionData) {
super(connectionData.getConnectionName(), connectionData.getUrl(), connectionData.getUserName(), connectionData
.getUserPassword());
init();
if (connectionData.getTruststorePath() != null) {
super.setTruststorePath(connectionData.getTruststorePath());
}
if (connectionData.getTruststorePassword() != null) {
super.setTruststorePassword(connectionData.getTruststorePassword());
}
if (connectionData.getMaxPollResultSize() > 0) {
super.setMaxPollResultSize(connectionData.getMaxPollResultSize());
}
super.setStartupConnect(connectionData.doesConnectOnStartup());
super.setAuthenticationBasic(connectionData.isAuthenticationBasic());
for (Data subscriptonData : connectionData.getSubscriptions()) {
if (subscriptonData instanceof SubscriptionData) {
super.addSubscription(new SubscriptionImpl(this, (SubscriptionData) subscriptonData));
}
}
super.setConnected(connectionData.isConnected());
}
private void init() {
// set default data
super.setAuthenticationBasic(ConnectionsProperties.DEFAULT_AUTHENTICATION_BASIC);
super.setTruststorePath(ConnectionsProperties.DEFAULT_TRUSTSTORE_PATH);
super.setTruststorePassword(ConnectionsProperties.DEFAULT_TRUSTSTORE_PASSWORD);
super.setMaxPollResultSize(ConnectionsProperties.DEFAULT_MAX_POLL_RESULT_SIZE);
super.setStartupConnect(ConnectionsProperties.DEFAULT_STARTUP_CONNECT);
mNeo4JDb = new Neo4JDatabase(super.getName());
}
@Override
public MapServerConnectionImpl copy() {
MapServerData dataCopy = super.copy();
MapServerConnectionImpl tmpCopy = new MapServerConnectionImpl(dataCopy);
return tmpCopy;
}
@Override
public MapServerConnectionImpl clone() {
return (MapServerConnectionImpl) super.clone();
}
@Override
public void connect() throws ConnectionException {
checkIsConnectionDisconnected();
String url = super.getUrl();
String userName = super.getUserName();
String userPassword = super.getUserPassword();
String truststorePath = super.getTruststorePath();
String truststorePassword = super.getTruststorePassword();
int maxPollResultSize = super.getMaxPollResultSize();
initSsrc(url, userName, userPassword, truststorePath, truststorePassword);
initSession(maxPollResultSize);
super.setConnected(true);
}
@Override
public void disconnect() throws ConnectionException {
checkIsConnectionEstablished();
try {
LOGGER.trace("endSession() ...");
mSsrc.endSession();
LOGGER.debug("endSession() OK");
LOGGER.trace("closeTcpConnection() ...");
mSsrc.closeTcpConnection();
LOGGER.debug("closeTcpConnection() OK");
} catch (IfmapErrorResult e) {
throw new IfmapConnectionException(e);
} catch (CommunicationException e) {
throw new IfmapConnectionException(e);
} catch (IfmapException e) {
throw new IfmapConnectionException(e);
} finally {
resetConnection();
}
super.setConnected(false);
}
public void disconnectFromDB() {
LOGGER.trace("Stop Neo4JDatabase...");
mNeo4JDb.stop();
LOGGER.info("Neo4JDatabase stopped");
}
@Override
public PollResult poll() throws ConnectionException {
checkIsConnectionEstablished();
try {
return mSsrc.getArc().poll();
} catch (IfmapErrorResult e) {
throw new IfmapConnectionException(e);
} catch (EndSessionException e) {
throw new ConnectionCloseException();
} catch (IfmapException e) {
throw new IfmapConnectionException(e);
}
}
@Override
public void startSubscription(String subscriptionName) throws ConnectionException {
boolean contains = false;
for (Data subscription : getSubscriptions()) {
if (subscription.getName().equals(subscriptionName)) {
contains = true;
((Subscription) subscription).startSubscription();
break;
}
}
if (!contains) {
throw new NoSavedSubscriptionException();
}
}
@Override
public void stopSubscription(String subscriptionName) throws ConnectionException {
boolean contains = false;
for (Data subscription : getSubscriptions()) {
if (subscription.getName().equals(subscriptionName)) {
contains = true;
((Subscription) subscription).stopSubscription();
break;
}
}
if (!contains) {
throw new NoSavedSubscriptionException();
}
}
@Override
public void stopAllSubscriptions() throws ConnectionException {
for (Data subData : getSubscriptions()) {
((Subscription) subData).stopSubscription();
}
}
private void subscribe(SubscribeRequest request) throws ConnectionException {
checkIsConnectionEstablished();
startUpdateService();
if ((request == null) || !request.getSubscribeElements().isEmpty()) {
try {
mSsrc.subscribe(request);
} catch (IfmapErrorResult e) {
throw new IfmapConnectionException(e);
} catch (IfmapException e) {
throw new IfmapConnectionException(e);
}
} else {
LOGGER.warn("Subscribe-Request was null or empty.");
}
}
@Override
public void subscribe(Subscription subscription, boolean update) throws ConnectionException {
SubscribeRequest subscribeRequest;
if (update) {
subscribeRequest = SubscriptionHelper.buildUpdateRequest(subscription);
} else {
subscribeRequest = SubscriptionHelper.buildDeleteRequest(subscription);
}
subscribe(subscribeRequest);
}
@Override
public String getConnectionName() {
return super.getName();
}
@Override
public GraphService getGraphService() {
return mNeo4JDb.getGraphService();
}
@Override
public String getPublisherId() throws ConnectionException {
checkIsConnectionEstablished();
return mSsrc.getPublisherId();
}
@Override
public String getSessionId() throws ConnectionException {
checkIsConnectionEstablished();
return mSsrc.getSessionId();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Connection: ").append(getConnectionName()).append(" | URL: ");
sb.append(getUrl()).append(" | User: ").append(getUserName());
return sb.toString();
}
private void initSsrc(String url, String user, String userPass, String truststore, String truststorePassword)
throws IfmapConnectionException {
LOGGER.trace("init SSRC ...");
try {
BasicAuthConfig config = new BasicAuthConfig(url, user, userPass, truststore, truststorePassword, true,
120 * 1000);
mSsrc = IfmapJ.createSsrc(config);
} catch (InitializationException e) {
resetConnection();
throw new IfmapConnectionException(e);
}
LOGGER.debug("init SSRC OK");
}
private void initSession(int maxPollResultSize) throws IfmapConnectionException {
LOGGER.trace("creating new SSRC session ...");
try {
mSsrc.newSession(maxPollResultSize);
} catch (IfmapErrorResult e) {
resetConnection();
throw new IfmapConnectionException(e);
} catch (IfmapException e) {
resetConnection();
throw new IfmapConnectionException(e);
}
LOGGER.debug("new SSRC session OK");
}
private void checkIsConnectionEstablished() throws NotConnectedException {
if ((mSsrc == null) || !super.isConnected() || (mSsrc.getSessionId() == null)) {
NotConnectedException e = new NotConnectedException();
LOGGER.error(e.toString());
resetConnection();
throw e;
}
}
private void checkIsConnectionDisconnected() throws ConnectionEstablishedException {
if ((mSsrc != null) && super.isConnected() && (mSsrc.getSessionId() != null)) {
throw new ConnectionEstablishedException();
}
}
private void resetConnection() {
LOGGER.trace("resetConnection() ...");
super.setConnected(false);
mSsrc = null;
// disabled all subscriptions
for (Data subscriptionData : super.getSubscriptions()) {
if (subscriptionData instanceof Subscription) {
Subscription subscription = (Subscription) subscriptionData;
subscription.setActive(false);
}
}
LOGGER.trace("... resetConnection() OK");
}
private void startUpdateService() throws ConnectionException {
String connectionName = getConnectionName();
if ((mUpdateThread == null) || !mUpdateThread.isAlive()) {
LOGGER.trace("start UpdateService from connection " + connectionName + " ...");
checkIsConnectionEstablished();
if (mUpdateService == null) {
mUpdateService = new UpdateService(this, mNeo4JDb.getWriter(), new InMemoryIdentifierFactory(),
new InMemoryMetadataFactory());
}
mUpdateThread = new Thread(mUpdateService, "UpdateThread-" + connectionName);
mUpdateThread.start();
LOGGER.debug("UpdateService for connection " + connectionName + " started");
}
}
}