blob: e12c9985713e8f6be1900daa9b235b0b56eaf8a0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
* wesendon
* boehlke
******************************************************************************/
package org.eclipse.emf.emfstore.internal.server.core;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.EnumMap;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionElement;
import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPoint;
import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.internal.server.EMFStore;
import org.eclipse.emf.emfstore.internal.server.accesscontrol.AuthorizationControl;
import org.eclipse.emf.emfstore.internal.server.core.helper.EmfStoreMethod;
import org.eclipse.emf.emfstore.internal.server.core.helper.EmfStoreMethod.MethodId;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.EMFStorePropertiesSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.EPackageSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.FileTransferSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.HistorySubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.ProjectPropertiesSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.ProjectSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.UserSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.core.subinterfaces.VersionSubInterfaceImpl;
import org.eclipse.emf.emfstore.internal.server.exceptions.FatalESException;
import org.eclipse.emf.emfstore.internal.server.model.ServerSpace;
import org.eclipse.emf.emfstore.server.exceptions.ESException;
import org.eclipse.emf.emfstore.server.observer.ESServerCallObserver;
/**
* This is the main implementation of {@link EMFStore}.
*
* @author wesendon
* @see EMFStore
*/
// TODO: internal
public class EMFStoreImpl extends AbstractEmfstoreInterface implements InvocationHandler {
/**
* Represents a method in a subinterface.
*
* @author boehlke
*/
private class SubInterfaceMethod {
private final AbstractSubEmfstoreInterface iface;
private final Method method;
public SubInterfaceMethod(AbstractSubEmfstoreInterface iface, Method m) {
method = m;
this.iface = iface;
}
/**
* @return the iface
*/
public AbstractSubEmfstoreInterface getIface() {
return iface;
}
/**
* @return the method
*/
public Method getMethod() {
return method;
}
}
private EnumMap<MethodId, SubInterfaceMethod> subInterfaceMethods;
private final Set<ESServerCallObserver> serverCallObservers;
/**
* Default constructor.
*
* @param serverSpace
* the serverspace
* @param authorizationControl
* the accesscontrol
* @throws FatalESException
* in case of failure
*/
public EMFStoreImpl(ServerSpace serverSpace, AuthorizationControl authorizationControl)
throws FatalESException {
super(serverSpace, authorizationControl);
serverCallObservers = initServerCallObservers();
}
/**
*
*/
private Set<ESServerCallObserver> initServerCallObservers() {
final Set<ESServerCallObserver> result = new LinkedHashSet<ESServerCallObserver>();
for (final ESExtensionElement e : new ESExtensionPoint("org.eclipse.emf.emfstore.server.serverCallObserver")
.getExtensionElements()) {
final ESServerCallObserver observer = e.getClass("class", ESServerCallObserver.class);
if (observer != null) {
result.add(observer);
}
}
return result;
}
/**
* {@inheritDoc}
*/
@Override
protected void initSubInterfaces() throws FatalESException {
subInterfaceMethods = new EnumMap<MethodId, SubInterfaceMethod>(MethodId.class);
addSubInterface(new HistorySubInterfaceImpl(this));
addSubInterface(new ProjectSubInterfaceImpl(this));
addSubInterface(new UserSubInterfaceImpl(this));
addSubInterface(new VersionSubInterfaceImpl(this));
addSubInterface(new FileTransferSubInterfaceImpl(this));
addSubInterface(new ProjectPropertiesSubInterfaceImpl(this));
addSubInterface(new EMFStorePropertiesSubInterfaceImpl(this));
addSubInterface(new EPackageSubInterfaceImpl(this));
}
@Override
protected void addSubInterface(AbstractSubEmfstoreInterface iface) {
super.addSubInterface(iface);
for (final Method method : iface.getClass().getMethods()) {
final EmfStoreMethod implSpec = method.getAnnotation(EmfStoreMethod.class);
if (implSpec != null) {
subInterfaceMethods.put(implSpec.value(), new SubInterfaceMethod(iface, method));
}
}
}
/**
*
* {@inheritDoc}
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object obj, final Method method, final Object[] args) throws ESException {
final MethodInvocation methodInvocation = new MethodInvocation(method.getName(), args);
getAuthorizationControl().checkAccess(methodInvocation);
notifyServerCallObservers(new ServerCallObserverNotifier() {
public void notify(ESServerCallObserver observer) {
observer.notifyPreServerCallExecution(method, args);
}
});
final SubInterfaceMethod subIfaceMethod = subInterfaceMethods.get(methodInvocation.getType());
try {
final Object result = subIfaceMethod.getIface().execute(subIfaceMethod.getMethod(), args);
notifyServerCallObservers(new ServerCallObserverNotifier() {
public void notify(ESServerCallObserver observer) {
observer.notifyPostServerCallExecution(method, args, result);
}
});
return result;
// notify observers about exceptions and rethrow exception
} catch (final ESException esException) {
notifyServerCallObservers(new ServerCallObserverNotifier() {
public void notify(ESServerCallObserver observer) {
observer.notifyServerCallExecutionESExceptionFailure(method, args, esException);
}
});
throw esException;
// BEGIN SUPRESS CATCH EXCEPTION
} catch (final RuntimeException runtimeException) {
// END SUPRESS CATCH EXCEPTION
notifyServerCallObservers(new ServerCallObserverNotifier() {
public void notify(ESServerCallObserver observer) {
observer.notifyServerCallExecutionRuntimeExceptionFailure(method, args, runtimeException);
}
});
throw runtimeException;
}
}
/**
* Notify the observers with the given notifier.
*
* @param serverCallObserverNotifier the notifier
*/
private void notifyServerCallObservers(ServerCallObserverNotifier serverCallObserverNotifier) {
for (final ESServerCallObserver callObserver : serverCallObservers) {
try {
serverCallObserverNotifier.notify(callObserver);
// BEGIN SUPRESS CATCH EXCEPTION
} catch (final RuntimeException runtimeException) {
// END SUPRESS CATCH EXCEPTION
ModelUtil.logWarning("Server Call Observer Notification failed with exception!", runtimeException);
}
}
}
/**
* creates a dynamic proxy backed by EmfStoreImpl.
*
* @param serverSpace the server space
* @param accessControl an access control instance
* @return an instance of emfstore
* @throws IllegalArgumentException thrown by Proxy.newInstance
* @throws FatalESException thrown if something fatal happens
*/
public static EMFStore createInterface(ServerSpace serverSpace, AuthorizationControl accessControl)
throws IllegalArgumentException, FatalESException {
return (EMFStore) Proxy.newProxyInstance(EMFStoreImpl.class.getClassLoader(), new Class[] { EMFStore.class },
new EMFStoreImpl(serverSpace, accessControl));
}
}