| /******************************************************************************* |
| * Copyright (c) 2015 EclipseSource Muenchen GmbH and others. |
| * |
| * 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: |
| * Edgar Mueller - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.emf.emfstore.internal.server.core.subinterfaces; |
| |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.text.MessageFormat; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.emfstore.internal.common.model.util.FileUtil; |
| import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.ChangePackage; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.FileBasedChangePackage; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.VersioningFactory; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation; |
| import org.eclipse.emf.emfstore.server.ESCloseableIterable; |
| import org.eclipse.emf.emfstore.server.exceptions.ESException; |
| |
| import com.google.common.base.Optional; |
| |
| /** |
| * Adapter that is meant to be attached to a session and stores all change package fragments. |
| * |
| * @author emueller |
| * |
| */ |
| public class ChangePackageFragmentUploadAdapter extends AdapterImpl { |
| |
| // maps proxy ID to file-based change package |
| private final Map<String, File> proxyIdToChangePackageFragments = new LinkedHashMap<String, File>(); |
| private final Map<String, File> proxyIdToCompletedChangePackages = new LinkedHashMap<String, File>(); |
| |
| /** |
| * Adds a single fragment. |
| * |
| * @param proxyId |
| * the ID identifying the list of fragments this fragment belongs to |
| * @param fragment |
| * the actual fragment to be added |
| * @throws ESException in case the fragment could not be added |
| */ |
| public void addFragment(String proxyId, List<String> fragment) throws ESException { |
| File file = proxyIdToChangePackageFragments.get(proxyId); |
| if (file == null) { |
| file = new File(FileUtil.createLocationForTemporaryChangePackage() + ".temp"); //$NON-NLS-1$ |
| proxyIdToChangePackageFragments.put(proxyId, file); |
| } |
| FileWriter writer = null; |
| try { |
| writer = new FileWriter(file, true); |
| for (final String str : fragment) { |
| writer.write(str + System.getProperty("line.separator")); //$NON-NLS-1$ |
| } |
| } catch (final IOException ex) { |
| throw new ESException(Messages.ChangePackageFragmentUploadAdapter_SplittingFailed, ex); |
| } finally { |
| if (writer != null) { |
| try { |
| writer.close(); |
| } catch (final IOException ex) { |
| throw new ESException(Messages.ChangePackageFragmentAdapter_SaveChangePackageFailed, ex); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Mark a list of change package as completed. |
| * |
| * @param proxyId |
| * the ID of the set of change package fragments that is supposed to be completed |
| * @throws ESException in case |
| */ |
| public void markAsComplete(String proxyId) throws ESException { |
| final File possiblyCompletedChangePackage = proxyIdToCompletedChangePackages.get(proxyId); |
| final File fileBasedChangePackage = proxyIdToChangePackageFragments.get(proxyId); |
| |
| if (possiblyCompletedChangePackage != null) { |
| throw new ESException(Messages.ChangePackageFragmentUploadAdapter_ChangePackageAlreadyComplete); |
| } |
| |
| if (fileBasedChangePackage == null) { |
| throw new ESException( |
| MessageFormat.format( |
| Messages.ChangePackageFragmentUploadAdapter_NoChangePackageFragmentsFound, proxyId)); |
| } |
| |
| proxyIdToCompletedChangePackages.put(proxyId, fileBasedChangePackage); |
| proxyIdToChangePackageFragments.remove(proxyId); |
| } |
| |
| /** |
| * Returns the aggregated change package. Fragments considered as complete need to be marked as such by |
| * calling {{@link #markAsComplete(String)}. |
| * |
| * @param proxyId |
| * the ID that identifies a list of change package fragments from which the change package |
| * will be created |
| * @return the aggregated {@link ChangePackage} as an {@link Optional} |
| */ |
| public Optional<ChangePackage> convertFileBasedToInMemoryChangePackage(String proxyId) { |
| final File file = proxyIdToCompletedChangePackages.get(proxyId); |
| if (file == null) { |
| return Optional.absent(); |
| } |
| final FileBasedChangePackage cp = VersioningFactory.eINSTANCE.createFileBasedChangePackage(); |
| final String path = file.getAbsolutePath().substring(0, |
| file.getAbsolutePath().length() - ".temp".length()); //$NON-NLS-1$ |
| cp.setFilePath(path); |
| |
| final ESCloseableIterable<AbstractOperation> operationsHandle = cp.operations(); |
| final ChangePackage changePackage = VersioningFactory.eINSTANCE.createChangePackage(); |
| try { |
| for (final AbstractOperation operation : operationsHandle.iterable()) { |
| changePackage.add(ModelUtil.clone(operation)); |
| } |
| } finally { |
| operationsHandle.close(); |
| } |
| |
| return Optional.of(changePackage); |
| } |
| |
| /** |
| * Returns the temporary file based changepackage for the given proxy id, if present. The change package is backed |
| * by temporary files on server side, so {@link FileBasedChangePackage#move(String)} might be needed. |
| * |
| * @param proxyId the ID that identifies the {@link FileBasedChangePackage} |
| * @return the file based change package as an {@link Optional} |
| */ |
| public Optional<FileBasedChangePackage> getFileBasedChangePackage(String proxyId) { |
| final File file = proxyIdToCompletedChangePackages.get(proxyId); |
| if (file == null) { |
| return Optional.absent(); |
| } |
| final FileBasedChangePackage cp = VersioningFactory.eINSTANCE.createFileBasedChangePackage(); |
| final String path = file.getAbsolutePath().substring(0, |
| file.getAbsolutePath().length() - ".temp".length()); //$NON-NLS-1$ |
| cp.setFilePath(path); |
| try { |
| cp.save(); |
| } catch (final IOException ex) { |
| // TODO: use checked exception? |
| throw new IllegalStateException(ex); |
| } |
| return Optional.of(cp); |
| } |
| |
| /** |
| * Removes the completed change package matching the given ID. |
| * |
| * @param proxyId |
| * the ID of the change package proxy |
| */ |
| public void clearCompleted(final String proxyId) { |
| proxyIdToCompletedChangePackages.remove(proxyId); |
| } |
| } |