/**
* Copyright (c) 2013-2016 Angelo ZERRR and Genuitec LLC.
* 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:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
* Piotr Tomiak <piotr@genutiec.com> - asynchronous request processing and
- * refactoring of collectors API
*/
package tern.server;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import tern.ITernFileSynchronizer;
import tern.ITernProject;
import tern.TernException;
import tern.server.protocol.ITernResultsCollector;
import tern.server.protocol.TernDoc;
import tern.server.protocol.push.IMessageHandler;
/**
* Abstract tern server.
*
*/
public abstract class AbstractTernServer implements ITernServer {
private final ITernProject project;
private final List<ITernServerListener> serverListeners;
private final Map<String, List<IMessageHandler>> messageListeners;
private boolean dataAsJsonString;
private boolean dispose;
private boolean loadingLocalPlugins;
private ITernServerRequestProcessor reqProcessor;
private ReentrantReadWriteLock stateLock = new ReentrantReadWriteLock();
public AbstractTernServer(ITernProject project) {
this.project = project;
this.serverListeners = new ArrayList<ITernServerListener>();
this.messageListeners = new HashMap<String, List<IMessageHandler>>();
final ITernFileSynchronizer fileSynchronizer = getFileSynchronizer();
if (fileSynchronizer != null) {
this.addServerListener(new TernServerAdapter() {
@Override
public void onStop(ITernServer server) {
fileSynchronizer.cleanIndexedFiles();
}
});
}
}
protected void beginReadState() {
stateLock.readLock().lock();
}
protected void endReadState() {
stateLock.readLock().unlock();
}
protected void beginWriteState() {
stateLock.writeLock().lock();
}
protected void endWriteState() {
stateLock.writeLock().unlock();
}
public boolean isDataAsJsonString() {
return dataAsJsonString;
}
public void setDataAsJsonString(boolean dataAsJsonString) {
this.dataAsJsonString = dataAsJsonString;
}
@Override
public void addServerListener(ITernServerListener listener) {
synchronized (serverListeners) {
serverListeners.add(listener);
}
}
@Override
public void removeServerListener(ITernServerListener listener) {
synchronized (serverListeners) {
serverListeners.remove(listener);
}
}
protected void fireStartServer() {
synchronized (serverListeners) {
for (ITernServerListener listener : serverListeners) {
listener.onStart(this);
}
}
}
protected void fireEndServer() {
synchronized (serverListeners) {
for (ITernServerListener listener : serverListeners) {
listener.onStop(this);
}
}
}
@Override
public final void dispose() {
beginWriteState();
try {
if (!isDisposed()) {
this.dispose = true;
doDispose();
// fireEndServer();
}
} finally {
endWriteState();
}
}
@Override
public boolean isDisposed() {
return dispose;
}
protected abstract void doDispose();
@Override
public ITernFileSynchronizer getFileSynchronizer() {
if (project != null) {
return project.getFileSynchronizer();
}
return null;
}
public ITernProject getProject() {
return project;
}
@Override
public void addFile(String name, String text) {
addFile(name, text, null);
}
@Override
public void setLoadingLocalPlugins(boolean loadingLocalPlugins) {
this.loadingLocalPlugins = loadingLocalPlugins;
}
@Override
public boolean isLoadingLocalPlugins() {
return loadingLocalPlugins;
}
@Override
public void request(TernDoc doc, ITernResultsCollector collector)
throws TernException {
try {
if (reqProcessor == null) {
// always provide request processor
reqProcessor = new SynchronousRequestProcessor(this);
}
reqProcessor.processRequest(doc, collector);
} catch (Exception e) {
getFileSynchronizer().uploadFailed(doc);
if (e instanceof TernException) {
throw (TernException) e;
}
throw new TernException(e);
}
}
@Override
public ITernServerRequestProcessor getRequestProcessor() {
return reqProcessor;
}
@Override
public void setRequestProcessor(ITernServerRequestProcessor reqProcessor) {
this.reqProcessor = reqProcessor;
}
@Override
public void on(String type, IMessageHandler handler) {
synchronized (messageListeners) {
List<IMessageHandler> handlers = messageListeners.get(type);
if (handlers == null) {
handlers = new ArrayList<IMessageHandler>();
messageListeners.put(type, handlers);
}
if (!handlers.contains(handler)) {
handlers.add(handler);
}
}
}
@Override
public void off(String type, IMessageHandler handler) {
synchronized (messageListeners) {
List<IMessageHandler> handlers = messageListeners.get(type);
if (handlers != null) {
handlers.remove(handler);
}
}
}
protected void fireOnMessage(String type, Object jsonObject) {
synchronized (messageListeners) {
List<IMessageHandler> handlers = messageListeners.get(type);
if (handlers != null) {
for (IMessageHandler handler : handlers) {
handler.handleMessage(jsonObject, getJSONObjectHelper());
}
}
}
}
}