/******************************************************************************* * 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: ******************************************************************************/ package org.eclipse.emf.emfstore.server.core; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.emfstore.common.filetransfer.FileChunk; import org.eclipse.emf.emfstore.common.filetransfer.FileTransferInformation; import org.eclipse.emf.emfstore.common.model.EMFStoreProperty; import org.eclipse.emf.emfstore.common.model.Project; import org.eclipse.emf.emfstore.server.EmfStore; import org.eclipse.emf.emfstore.server.OperationExecution; import org.eclipse.emf.emfstore.server.OperationExecution.OperationExecutionContext; import org.eclipse.emf.emfstore.server.accesscontrol.AuthorizationControl; import org.eclipse.emf.emfstore.server.accesscontrol.Permission; import org.eclipse.emf.emfstore.server.accesscontrol.PermissionProvider.InternalPermission; import org.eclipse.emf.emfstore.server.connection.xmlrpc.util.StaticOperationFactory; import org.eclipse.emf.emfstore.server.core.operation.OperationExecutor; import org.eclipse.emf.emfstore.server.core.operation.OperationHandler; import org.eclipse.emf.emfstore.server.core.operation.OrgUnitOperationExecutor; import org.eclipse.emf.emfstore.server.core.subinterfaces.EMFStorePropertiesSubInterfaceImpl; import org.eclipse.emf.emfstore.server.core.subinterfaces.FileTransferSubInterfaceImpl; import org.eclipse.emf.emfstore.server.core.subinterfaces.HistorySubInterfaceImpl; import org.eclipse.emf.emfstore.server.core.subinterfaces.ProjectPropertiesSubInterfaceImpl; import org.eclipse.emf.emfstore.server.core.subinterfaces.ProjectSubInterfaceImpl; import org.eclipse.emf.emfstore.server.core.subinterfaces.UserSubInterfaceImpl; import org.eclipse.emf.emfstore.server.core.subinterfaces.VersionSubInterfaceImpl; import org.eclipse.emf.emfstore.server.exceptions.AccessControlException; import org.eclipse.emf.emfstore.server.exceptions.EmfStoreException; import org.eclipse.emf.emfstore.server.exceptions.FatalEmfStoreException; import org.eclipse.emf.emfstore.server.exceptions.InvalidInputException; import org.eclipse.emf.emfstore.server.exceptions.InvalidVersionSpecException; import org.eclipse.emf.emfstore.server.model.ProjectHistory; import org.eclipse.emf.emfstore.server.model.ProjectId; import org.eclipse.emf.emfstore.server.model.ProjectInfo; import org.eclipse.emf.emfstore.server.model.ServerSpace; import org.eclipse.emf.emfstore.server.model.SessionId; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACGroup; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACOrgUnit; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACOrgUnitId; import org.eclipse.emf.emfstore.server.model.accesscontrol.ACUser; import org.eclipse.emf.emfstore.server.model.accesscontrol.OrgUnitProperty; import org.eclipse.emf.emfstore.server.model.accesscontrol.PermissionSet; import org.eclipse.emf.emfstore.server.model.operation.AddTagOperation; import org.eclipse.emf.emfstore.server.model.operation.CreateProjectByImportOperation; import org.eclipse.emf.emfstore.server.model.operation.CreateProjectOperation; import org.eclipse.emf.emfstore.server.model.operation.CreateVersionOperation; import org.eclipse.emf.emfstore.server.model.operation.DeleteProjectOperation; import org.eclipse.emf.emfstore.server.model.operation.FileUploadOperation; import org.eclipse.emf.emfstore.server.model.operation.Operation; import org.eclipse.emf.emfstore.server.model.operation.RemoveTagOperation; import org.eclipse.emf.emfstore.server.model.operation.WritePropertiesOperation; import org.eclipse.emf.emfstore.server.model.versioning.ChangePackage; import org.eclipse.emf.emfstore.server.model.versioning.HistoryInfo; import org.eclipse.emf.emfstore.server.model.versioning.HistoryQuery; import org.eclipse.emf.emfstore.server.model.versioning.LogMessage; import org.eclipse.emf.emfstore.server.model.versioning.PrimaryVersionSpec; import org.eclipse.emf.emfstore.server.model.versioning.TagVersionSpec; import org.eclipse.emf.emfstore.server.model.versioning.VersionSpec; /** * This is the main implementation of {@link EmfStore}. * * @author wesendon * @see EmfStore */ public class EmfStoreImpl extends AbstractEmfstoreInterface implements EmfStore { /** * list of operation executors */ private List<OperationExecutor> executors = new ArrayList<OperationExecutor>(); /** * Default constructor. * * @param serverSpace * the serverspace * @param authorizationControl * the accesscontrol * @throws FatalEmfStoreException * in case of failure */ public EmfStoreImpl(ServerSpace serverSpace, AuthorizationControl authorizationControl) throws FatalEmfStoreException { super(serverSpace, authorizationControl); executors.add(new OrgUnitOperationExecutor(serverSpace, authorizationControl)); } /** * {@inheritDoc} */ @Override protected void initSubInterfaces() throws FatalEmfStoreException { 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)); } private void checkOperationPermissions(SessionId sessionId, Operation<?> op) throws AccessControlException { getAuthorizationControl().checkPermissions(sessionId, op); } /** * {@inheritDoc} */ public List<HistoryInfo> getHistoryInfo(SessionId sessionId, ProjectId projectId, HistoryQuery historyQuery) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, historyQuery); checkOperationPermissions(sessionId, StaticOperationFactory.createReadProjectOperation(projectId, historyQuery.getTarget())); return getSubInterface(HistorySubInterfaceImpl.class).getHistoryInfo(projectId, historyQuery); } /** * {@inheritDoc} */ public void addTag(SessionId sessionId, ProjectId projectId, PrimaryVersionSpec versionSpec, TagVersionSpec tag) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, versionSpec, tag, tag == null ? null : tag.getName()); AddTagOperation operation = StaticOperationFactory.createAddTagOperation(projectId, versionSpec, tag); checkOperationPermissions(sessionId, operation); getSubInterface(HistorySubInterfaceImpl.class).addTag(projectId, versionSpec, tag); } /** * {@inheritDoc} */ public void removeTag(SessionId sessionId, ProjectId projectId, PrimaryVersionSpec versionSpec, TagVersionSpec tag) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, versionSpec, tag); RemoveTagOperation operation = StaticOperationFactory.createRemoveTagOperation(projectId, versionSpec, tag); checkOperationPermissions(sessionId, operation); getSubInterface(HistorySubInterfaceImpl.class).removeTag(projectId, versionSpec, tag); } /** * {@inheritDoc} */ public ProjectInfo createEmptyProject(SessionId sessionId, String name, String description, LogMessage logMessage) throws EmfStoreException { sanityCheckObjects(sessionId, name, description, logMessage); CreateProjectOperation operation = StaticOperationFactory.createCreateProjectOperation(name, description, logMessage, null); checkOperationPermissions(sessionId, operation); ProjectInfo projectInfo = getSubInterface(ProjectSubInterfaceImpl.class).createProject(name, description, logMessage); return projectInfo; } /** * {@inheritDoc} */ public ProjectInfo createProject(SessionId sessionId, String name, String description, LogMessage logMessage, Project project) throws EmfStoreException { sanityCheckObjects(sessionId, name, description, logMessage, project); CreateProjectOperation operation = StaticOperationFactory.createCreateProjectOperation(name, description, logMessage, project); checkOperationPermissions(sessionId, operation); ProjectInfo projectInfo = getSubInterface(ProjectSubInterfaceImpl.class).createProject(name, description, logMessage, project); return projectInfo; } /** * {@inheritDoc} */ public void deleteProject(SessionId sessionId, ProjectId projectId, boolean deleteFiles) throws EmfStoreException { sanityCheckObjects(sessionId, projectId); DeleteProjectOperation operation = StaticOperationFactory.createDeleteProjectOperation(projectId, deleteFiles); checkOperationPermissions(sessionId, operation); getSubInterface(ProjectSubInterfaceImpl.class).deleteProject(projectId, deleteFiles); } /** * {@inheritDoc} */ public PrimaryVersionSpec createVersion(SessionId sessionId, ProjectId projectId, PrimaryVersionSpec baseVersionSpec, ChangePackage changePackage, LogMessage logMessage) throws EmfStoreException, InvalidVersionSpecException { sanityCheckObjects(sessionId, projectId, baseVersionSpec, changePackage, logMessage); CreateVersionOperation operation = StaticOperationFactory.createCreateVersionOperation(projectId, baseVersionSpec, changePackage, logMessage); checkOperationPermissions(sessionId, operation); ACUser user = getAuthorizationControl().resolveUser(sessionId); PrimaryVersionSpec newVersion = getSubInterface(VersionSubInterfaceImpl.class).createVersion(projectId, baseVersionSpec, changePackage, logMessage, user); return newVersion; } /** * {@inheritDoc} */ public List<ChangePackage> getChanges(SessionId sessionId, ProjectId projectId, VersionSpec source, VersionSpec target) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, source, target); checkOperationPermissions(sessionId, StaticOperationFactory.createReadProjectOperation(projectId, target)); return getSubInterface(VersionSubInterfaceImpl.class).getChanges(projectId, source, target); } /** * {@inheritDoc} */ public PrimaryVersionSpec resolveVersionSpec(SessionId sessionId, ProjectId projectId, VersionSpec versionSpec) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, versionSpec); checkOperationPermissions(sessionId, StaticOperationFactory.createReadProjectOperation(projectId, versionSpec)); return getSubInterface(VersionSubInterfaceImpl.class).resolveVersionSpec(projectId, versionSpec); } /** * {@inheritDoc} */ public Project getProject(SessionId sessionId, ProjectId projectId, VersionSpec versionSpec) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, versionSpec); checkOperationPermissions(sessionId, StaticOperationFactory.createReadProjectOperation(projectId, versionSpec)); return getSubInterface(ProjectSubInterfaceImpl.class).getProject(projectId, versionSpec); } /** * {@inheritDoc} */ public List<ProjectInfo> getProjectList(SessionId sessionId) throws EmfStoreException { sanityCheckObjects(sessionId); return getSubInterface(ProjectSubInterfaceImpl.class).getProjectList(sessionId); } /** * {@inheritDoc} */ public ProjectId importProjectHistoryToServer(SessionId sessionId, ProjectHistory projectHistory) throws EmfStoreException { sanityCheckObjects(sessionId, projectHistory); CreateProjectByImportOperation operation = StaticOperationFactory .createCreateProjectByImportOperation(projectHistory); checkOperationPermissions(sessionId, operation); ProjectId projectId = getSubInterface(ProjectSubInterfaceImpl.class).importProjectHistoryToServer( projectHistory); return projectId; } /** * {@inheritDoc} */ public ProjectHistory exportProjectHistoryFromServer(SessionId sessionId, ProjectId projectId) throws EmfStoreException { sanityCheckObjects(sessionId, projectId); checkOperationPermissions(sessionId, StaticOperationFactory.createReadProjectOperation(projectId, null)); return getSubInterface(ProjectSubInterfaceImpl.class).exportProjectHistoryFromServer(projectId); } /** * {@inheritDoc} */ public ACUser resolveUser(SessionId sessionId, ACOrgUnitId id) throws EmfStoreException { sanityCheckObjects(sessionId); return getSubInterface(UserSubInterfaceImpl.class).resolveUser(sessionId, id); } /** * {@inheritDoc} */ public FileChunk downloadFileChunk(SessionId sessionId, ProjectId projectId, FileTransferInformation fileInformation) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, fileInformation); checkOperationPermissions(sessionId, StaticOperationFactory.createFileDownloadOperation(projectId, fileInformation)); return getSubInterface(FileTransferSubInterfaceImpl.class).readChunk(projectId, fileInformation); } /** * {@inheritDoc} */ public FileTransferInformation uploadFileChunk(SessionId sessionId, ProjectId projectId, FileChunk fileChunk) throws EmfStoreException { sanityCheckObjects(sessionId, projectId, fileChunk, fileChunk.getFileInformation()); FileUploadOperation operation = StaticOperationFactory.createFileUploadOperation(projectId, fileChunk); checkOperationPermissions(sessionId, operation); FileTransferInformation chunk = getSubInterface(FileTransferSubInterfaceImpl.class).writeChunk(fileChunk, projectId); return chunk; } /** * {@inheritDoc} */ public void transmitProperty(SessionId sessionId, OrgUnitProperty changedProperty, ACUser user, ProjectId projectId) throws EmfStoreException { sanityCheckObjects(projectId, user, changedProperty); WritePropertiesOperation operation = StaticOperationFactory.createWritePropertiesOperation(projectId, null); checkOperationPermissions(sessionId, operation); getSubInterface(ProjectPropertiesSubInterfaceImpl.class).setProperty(changedProperty, user, projectId); } /** * {@inheritDoc} */ public List<EMFStoreProperty> getEMFProperties(SessionId sessionId, ProjectId projectId) throws EmfStoreException { sanityCheckObjects(sessionId, projectId); checkOperationPermissions(sessionId, StaticOperationFactory.createReadPropertiesOperation(projectId)); return getSubInterface(EMFStorePropertiesSubInterfaceImpl.class).getProperties(projectId); } /** * {@inheritDoc} */ public void transmitEMFProperties(SessionId sessionId, List<EMFStoreProperty> properties, ProjectId projectId) throws EmfStoreException { sanityCheckObjects(projectId, properties); WritePropertiesOperation operation = StaticOperationFactory.createWritePropertiesOperation(projectId, properties); checkOperationPermissions(sessionId, operation); EMFStorePropertiesSubInterfaceImpl temp = getSubInterface(EMFStorePropertiesSubInterfaceImpl.class); temp.setProperties(properties, projectId); } public PermissionSet getPermissionSet(SessionId sessionId) throws EmfStoreException { PermissionSet set = EcoreUtil.copy(getServerSpace().getPermissionSet()); for (ACUser user : set.getUsers()) { removeIfNotVisible(sessionId, user); } for (ACGroup group : set.getGroups()) { removeIfNotVisible(sessionId, group); } return set; } private void removeIfNotVisible(SessionId sessionId, ACOrgUnit orgUnit) throws InvalidInputException, AccessControlException { if (!getAuthorizationControl().hasPermissions(sessionId, StaticOperationFactory.createReadOrgUnitOperation(orgUnit.getId().getId()))) { EcoreUtil.delete(orgUnit); } } private void checkOperationPermission(SessionId sessionId, Operation<?> op) throws AccessControlException { getAuthorizationControl().checkSession(sessionId); getAuthorizationControl().checkPermissions(sessionId, op); } public <T> T executeOperation(final SessionId sessionId, Operation<T> op) throws EmfStoreException { checkOperationPermission(sessionId, op); OperationExecution<T, Operation<T>> execution = new OperationExecution<T, Operation<T>>(op, new OperationExecutionContext() { public SessionId getSessionId() { return sessionId; } }); findAndExecuteExecutionMethod(op.getClass(), execution); return execution.getResult(); } /** * * @param type * @param execution * @throws EmfStoreException * @throws FatalEmfStoreException */ private <O extends Operation<?>, E extends OperationExecution<?, O>> void findAndExecuteExecutionMethod( Class<O> type, E execution) throws EmfStoreException { for (OperationExecutor executor : executors) { for (Method method : executor.getClass().getMethods()) { OperationHandler annotation = method.getAnnotation(OperationHandler.class); if (annotation != null) { Set<Class<? extends Operation<?>>> classes = new HashSet<Class<? extends Operation<?>>>(); if (annotation.operationClass() != OperationHandler.DEFAULT.class) { classes.add(annotation.operationClass()); } classes.addAll(Arrays.asList(annotation.operationClasses())); for (Class<? extends Operation<?>> clazz : classes) { if (clazz.isAssignableFrom(type)) { try { method.invoke(executor, execution); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof EmfStoreException) { throw (EmfStoreException) e.getTargetException(); } } catch (Exception e) { // this is fatal, because execution method signature is wrong // TODO: report in more detail, perhaps decicated Exception throw new RuntimeException(e); } return; } } } } } throw new EmfStoreException("no handler for operation:" + execution.getOperation().getClass().getName()); } public List<Permission[]> getOperationPermissions(SessionId sessionId, Operation<?>[] operations) throws AccessControlException { List<Permission[]> permissions = new ArrayList<Permission[]>(); for (Operation<?> op : operations) { permissions .add(convert(getAuthorizationControl().getPermissions(sessionId, op)).toArray(new Permission[0])); } return permissions; } private List<Permission> convert(Collection<InternalPermission> permissions) { List<Permission> list = new ArrayList<Permission>(); for (InternalPermission internalPermission : permissions) { ProjectId projectId = internalPermission.getProjectId(); list.add(new Permission(internalPermission.getType().getId(), projectId == null ? null : projectId.getId())); } return list; } }