blob: 64efd22d92e9931f4b40dc18788e1b359af55434 [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:
* Otto von Wesendonk, Maximilian Koegel - initial API and implementation
* Johannes Faltermeier - URI related refactorings
******************************************************************************/
package org.eclipse.emf.emfstore.internal.server;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.MessageFormat;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;
import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.emfstore.common.ESResourceSetProvider;
import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionElement;
import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPoint;
import org.eclipse.emf.emfstore.common.extensionpoint.ESPriorityComparator;
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.accesscontrol.AccessControl;
import org.eclipse.emf.emfstore.internal.server.connection.ConnectionHandler;
import org.eclipse.emf.emfstore.internal.server.connection.xmlrpc.XmlRpcAdminConnectionHandler;
import org.eclipse.emf.emfstore.internal.server.connection.xmlrpc.XmlRpcConnectionHandler;
import org.eclipse.emf.emfstore.internal.server.core.AdminEmfStoreImpl;
import org.eclipse.emf.emfstore.internal.server.core.EMFStoreImpl;
import org.eclipse.emf.emfstore.internal.server.core.MonitorProvider;
import org.eclipse.emf.emfstore.internal.server.core.helper.EPackageHelper;
import org.eclipse.emf.emfstore.internal.server.core.helper.ResourceHelper;
import org.eclipse.emf.emfstore.internal.server.exceptions.FatalESException;
import org.eclipse.emf.emfstore.internal.server.exceptions.StorageException;
import org.eclipse.emf.emfstore.internal.server.model.ClientVersionInfo;
import org.eclipse.emf.emfstore.internal.server.model.ModelFactory;
import org.eclipse.emf.emfstore.internal.server.model.ProjectHistory;
import org.eclipse.emf.emfstore.internal.server.model.ServerSpace;
import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACUser;
import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.AccesscontrolFactory;
import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.roles.RolesFactory;
import org.eclipse.emf.emfstore.internal.server.model.versioning.BranchInfo;
import org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec;
import org.eclipse.emf.emfstore.internal.server.model.versioning.VersioningFactory;
import org.eclipse.emf.emfstore.internal.server.model.versioning.Versions;
import org.eclipse.emf.emfstore.internal.server.startup.MigrationManager;
import org.eclipse.emf.emfstore.internal.server.startup.PostStartupListener;
import org.eclipse.emf.emfstore.internal.server.startup.ServerHrefMigrator;
import org.eclipse.emf.emfstore.internal.server.startup.StartupListener;
import org.eclipse.emf.emfstore.internal.server.storage.ServerXMIResourceSetProvider;
import org.eclipse.emf.emfstore.server.ESDynamicModelProvider;
import org.eclipse.emf.emfstore.server.ESServerURIUtil;
import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator;
import org.eclipse.emf.emfstore.server.auth.ESPasswordHashGenerator.ESHashAndSalt;
import org.eclipse.emf.emfstore.server.exceptions.ESServerInitException;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
/**
* The {@link EMFStoreController} is controlling startup and shutdown of the
* EmfStore.
*
* @author koegel
* @author wesendonk
* @author jfaltermeier
*/
public class EMFStoreController implements IApplication, Runnable {
private static final String EMFSTORE_TXT_FILE = "emfstore.txt"; //$NON-NLS-1$
private static final String SUPERUSRE_DESCRIPTION = "default server admin (superuser)"; //$NON-NLS-1$
private static final String SUPERUSER_LAST_NAME = "user"; //$NON-NLS-1$
private static final String SUPERUSER_FIRST_NAME = "super"; //$NON-NLS-1$
private static final String RESOURCE_SET_PROVIDER = "org.eclipse.emf.emfstore.server.resourceSetProvider"; //$NON-NLS-1$
private static final String CONFIG_RESOURCE_KEY = "org.eclipse.emf.emfstore.server.configurationResource"; //$NON-NLS-1$
private static final String EMFSTORE_COMMON_BUNDLE = "org.eclipse.emf.emfstore.common.model"; //$NON-NLS-1$
private static final String ORG_ECLIPSE_EMF_EMFSTORE_SERVER_DYNAMIC_MODEL_PROVIDER = "org.eclipse.emf.emfstore.server.dynamicModelProvider"; //$NON-NLS-1$
/**
* The period of time in seconds between executing the clean memory task.
*/
private static EMFStoreController instance;
private EMFStore emfStore;
private AdminEmfStore adminEmfStore;
private AccessControl accessControl;
private Set<ConnectionHandler<? extends EMFStoreInterface>> connectionHandlers;
private ServerSpace serverSpace;
private Resource resource;
/**
* {@inheritDoc}
*
* @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
public synchronized Object start(IApplicationContext context) throws FatalESException {
run(true);
instance = null;
ModelUtil.logInfo(Messages.EMFStoreController_Server_Stopped);
return IApplication.EXIT_OK;
}
/**
* Run the server.
*
* @param waitForTermination
* true if the server should force the calling thread to wait for
* its termination
* @throws FatalESException
* if the server fails fatally
*/
public synchronized void run(boolean waitForTermination) throws FatalESException {
if (instance != null) {
throw new FatalESException(Messages.EMFStoreController_EMFStore_Controller_Already_Running);
}
instance = this;
serverHeader();
initLogging();
// copy es.properties file to workspace if not existent
copyFileToWorkspace(ServerConfiguration.getConfFile(), ServerConfiguration.ES_PROPERTIES,
Messages.EMFStoreController_Could_Not_Copy_Properties_File,
Messages.EMFStoreController_Default_Properties_File_Copied);
final Properties properties = initProperties();
assureSuperUserPasswordIsSet(properties);
logGeneralInformation();
registerDynamicModels();
serverSpace = initServerSpace(Boolean.getBoolean("emfstore.migration")); //$NON-NLS-1$
if (serverSpace == null) {
return;
}
initializeBranchesIfRequired(serverSpace);
handleStartupListener();
accessControl = initAccessControl(serverSpace);
// TODO: ugly
emfStore = EMFStoreImpl.createInterface(serverSpace, accessControl);
adminEmfStore = new AdminEmfStoreImpl(serverSpace, accessControl);
// copy keystore file to workspace if not existent
copyFileToWorkspace(ServerConfiguration.getServerKeyStorePath(), ServerConfiguration.SERVER_KEYSTORE_FILE,
Messages.EMFStoreController_Failed_To_Copy_Keystore, Messages.EMFStoreController_Keystore_Copied);
connectionHandlers = initConnectionHandlers();
handlePostStartupListener();
registerShutdownHook();
if (ServerConfiguration.isUserPasswordMigrationRequired()) {
performDummyLogin();
}
ModelUtil.logInfo(Messages.EMFStoreController_Init_Complete);
ModelUtil.logInfo(Messages.EMFStoreController_Server_Running);
if (waitForTermination) {
waitForTermination();
}
}
/**
* Verify a dummy user in order to trigger an eager startup of the user verifiers.
*/
private void performDummyLogin() {
final ClientVersionInfo clientVersionInfo = ModelFactory.eINSTANCE.createClientVersionInfo();
clientVersionInfo.setVersion("1.0.0."); //$NON-NLS-1$ // actual version is unimportant
getAccessControl().getLoginService().verifyUser("", "", clientVersionInfo.toAPI()); //$NON-NLS-1$//$NON-NLS-2$
}
private void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
stopServer();
}
});
}
private void logGeneralInformation() {
ModelUtil.logInfo(Messages.EMFStoreController_Server_Home + ServerConfiguration.getServerHome());
ModelUtil.logInfo(MessageFormat.format(
Messages.EMFStoreController_JVM_Max_Memory, Runtime.getRuntime().maxMemory() / 1000000));
}
private void initializeBranchesIfRequired(ServerSpace serverSpace) throws FatalESException {
for (final ProjectHistory project : serverSpace.getProjects()) {
if (project.getBranches().size() == 0) {
// create branch information
final BranchInfo branchInfo = VersioningFactory.eINSTANCE.createBranchInfo();
branchInfo.setName(VersionSpec.BRANCH_DEFAULT_NAME);
branchInfo.setHead(ModelUtil.clone(project.getLastVersion().getPrimarySpec()));
// set branch source to 0 since no branches can have existed
branchInfo.setSource(ModelUtil.clone(Versions.createPRIMARY(VersionSpec.BRANCH_DEFAULT_NAME, 0)));
project.getBranches().add(branchInfo);
new ResourceHelper(serverSpace).save(project);
}
}
}
// delegates loading of dynamic models to the resource set provider
private void registerDynamicModels() {
final ESExtensionPoint extensionPoint = new ESExtensionPoint(
ORG_ECLIPSE_EMF_EMFSTORE_SERVER_DYNAMIC_MODEL_PROVIDER,
true, new ESPriorityComparator("priority", true)); //$NON-NLS-1$
final ESDynamicModelProvider dynamicModelProvider = extensionPoint.getElementWithHighestPriority().getClass(
"class", ESDynamicModelProvider.class); //$NON-NLS-1$
final List<EPackage> models = dynamicModelProvider.getDynamicModels();
for (final EPackage model : models) {
EPackage.Registry.INSTANCE.put(model.getNsURI(), model);
final List<EPackage> packages = EPackageHelper.getAllSubPackages(model);
for (final EPackage subPkg : packages) {
EPackage.Registry.INSTANCE.put(subPkg.getNsURI(), subPkg);
}
ModelUtil.logInfo(
MessageFormat.format(Messages.EMFStoreController_Dynamic_Model_Loaded, model.getNsURI()));
}
}
private void initLogging() {
Platform.getLog(Platform.getBundle(EMFSTORE_COMMON_BUNDLE)).addLogListener(new ILogListener() {
public void logging(IStatus status, String plugin) {
if (status.getSeverity() == IStatus.INFO) {
System.out.println(status.getMessage());
} else if (!status.isOK()) {
System.err.println(status.getMessage());
final Throwable exception = status.getException();
if (exception != null) {
exception.printStackTrace(System.err);
}
}
}
});
}
private void handleStartupListener() {
final String property = ServerConfiguration.getProperties().getProperty(
ServerConfiguration.LOAD_STARTUP_LISTENER,
ServerConfiguration.LOAD_STARTUP_LISTENER_DEFAULT);
if (Boolean.TRUE.toString().equals(property)) {
ModelUtil.logInfo("Notifying startup listener"); //$NON-NLS-1$
for (final StartupListener listener : ServerConfiguration.getStartupListeners()) {
listener.startedUp(serverSpace.getProjects());
}
}
}
private void handlePostStartupListener() {
final String property = ServerConfiguration.getProperties().getProperty(
ServerConfiguration.LOAD_POST_STARTUP_LISTENER, ServerConfiguration.LOAD_STARTUP_LISTENER_DEFAULT);
if (Boolean.TRUE.toString().equals(property)) {
ModelUtil.logInfo("Notifying post startup listener"); //$NON-NLS-1$
for (final PostStartupListener listener : ServerConfiguration.getPostStartupListeners()) {
listener.postStartUp(serverSpace, accessControl, connectionHandlers);
}
}
}
private void copyFileToWorkspace(String target, String source, String failure, String success) {
final File targetFile = new File(target);
if (!targetFile.exists()) {
// check if the custom configuration resources are provided and if,
// copy them to place
final ESExtensionPoint extensionPoint = new ESExtensionPoint(
CONFIG_RESOURCE_KEY);
final ESExtensionElement element = extensionPoint.getFirst();
if (element != null) {
final String attribute = element.getAttribute(targetFile.getName());
if (attribute != null) {
try {
FileUtil.copyFile(new URL("platform:/plugin/" //$NON-NLS-1$
+ element.getIConfigurationElement().getNamespaceIdentifier() + "/" + attribute) //$NON-NLS-1$
.openConnection().getInputStream(),
targetFile);
return;
} catch (final IOException e) {
ModelUtil.logWarning(
MessageFormat.format(Messages.EMFStoreController_Copy_From_To, source, target), e);
}
}
}
// Guess not, lets copy the default configuration resources
try {
FileUtil.copyFile(getClass().getResourceAsStream(source), targetFile);
} catch (final IOException e) {
ModelUtil.logWarning(
MessageFormat.format("Copy of file from {0} to {1} failed.", source, target), e); //$NON-NLS-1$
}
}
}
private Set<ConnectionHandler<? extends EMFStoreInterface>> initConnectionHandlers() throws FatalESException {
final Set<ConnectionHandler<? extends EMFStoreInterface>> connectionHandlers = new LinkedHashSet<ConnectionHandler<? extends EMFStoreInterface>>();
// crate XML RPC connection handlers
try {
final XmlRpcConnectionHandler xmlRpcConnectionHander = new XmlRpcConnectionHandler();
xmlRpcConnectionHander.init(emfStore, accessControl);
connectionHandlers.add(xmlRpcConnectionHander);
final XmlRpcAdminConnectionHandler xmlRpcAdminConnectionHander = new XmlRpcAdminConnectionHandler();
xmlRpcAdminConnectionHander.init(adminEmfStore, accessControl);
connectionHandlers.add(xmlRpcAdminConnectionHander);
} catch (final ESServerInitException ex) {
throw new FatalESException(Messages.EMFStoreController_ConnectionHandlersInitException, ex);
}
return connectionHandlers;
}
private ServerSpace initServerSpace(boolean migrationMode) throws FatalESException {
final ESResourceSetProvider resourceSetProvider = getResourceSetProvider();
final ResourceSet resourceSet = resourceSetProvider.getResourceSet();
final URI serverspaceURI = ESServerURIUtil.createServerSpaceURI();
// will be used only in case of ServerXMIResourceProvider, but maybe
// a more generic mechanism to remove any corrupt projects would make sense
if (!resourceSet.getURIConverter().exists(serverspaceURI, null)) {
try {
resource = resourceSet.createResource(serverspaceURI);
final ServerSpace serverspace = ModelFactory.eINSTANCE.createServerSpace();
resource.getContents().add(serverspace);
ModelUtil.saveResource(resource, ModelUtil.getResourceLogger());
} catch (final IOException e) {
throw new FatalESException(Messages.EMFStoreController_Could_Not_Init_XMLResource, e);
}
} else {
// hrefs are persisted differently in 1.1+ in comparison to 1.0
// migrate, if needed, before loading
if (resourceSetProvider instanceof ServerXMIResourceSetProvider) {
if (!new ServerHrefMigrator().migrate()) {
throw new FatalESException(Messages.EMFStoreController_Error_During_Migration);
}
}
/* file has been fixed. check if metamodel migration is needed */
if (migrationMode) {
MigrationManager.migrate(getResourceSetProvider().getResourceSet(),
!ServerConfiguration.useFileBasedChangePackageOnServer());
return null;
}
resource = resourceSet.createResource(serverspaceURI);
}
try {
resource.load(ModelUtil.getResourceLoadOptions());
} catch (final IOException e) {
throw new FatalESException(StorageException.NOLOAD, e);
}
ServerSpace result = null;
final EList<EObject> contents = resource.getContents();
for (final EObject content : contents) {
if (content instanceof ServerSpace) {
result = (ServerSpace) content;
break;
}
}
if (result != null) {
result.setResource(resource);
} else {
// if no serverspace can be loaded, create one
ModelUtil.logInfo(Messages.EMFStoreController_Creating_Initial_ServerSpace);
result = ModelFactory.eINSTANCE.createServerSpace();
result.setResource(resource);
resource.getContents().add(result);
try {
result.save();
} catch (final IOException e) {
throw new FatalESException(StorageException.NOSAVE, e);
}
}
return result;
}
/**
* @return
*/
private ESResourceSetProvider getResourceSetProvider() {
final ESExtensionPoint extensionPoint = new ESExtensionPoint(
RESOURCE_SET_PROVIDER,
true, new ESPriorityComparator("priority", true)); //$NON-NLS-1$
final ESResourceSetProvider resourceSetProvider = extensionPoint.getElementWithHighestPriority().getClass(
"class", //$NON-NLS-1$
ESResourceSetProvider.class);
return resourceSetProvider;
}
/**
* Return the singleton instance of EmfStoreControler.
*
* @return the instance
*/
public static EMFStoreController getInstance() {
return instance;
}
private static synchronized AccessControl initAccessControl(ServerSpace serverSpace) throws FatalESException {
setSuperUser(serverSpace);
return new AccessControl(serverSpace);
}
private static void setSuperUser(ServerSpace serverSpace) throws FatalESException {
final String superuser = ServerConfiguration.getProperties().getProperty(ServerConfiguration.SUPER_USER,
ServerConfiguration.SUPER_USER_DEFAULT);
for (final ACUser user : serverSpace.getUsers()) {
if (user.getName().equals(superuser)) {
return;
}
}
final ACUser superUser = AccesscontrolFactory.eINSTANCE.createACUser();
superUser.setName(superuser);
superUser.setFirstName(SUPERUSER_FIRST_NAME);
superUser.setLastName(SUPERUSER_LAST_NAME);
superUser.setDescription(SUPERUSRE_DESCRIPTION);
superUser.getRoles().add(RolesFactory.eINSTANCE.createServerAdmin());
serverSpace.getUsers().add(superUser);
try {
serverSpace.save();
} catch (final IOException e) {
throw new FatalESException(StorageException.NOSAVE, e);
}
ModelUtil.logInfo(Messages.EMFStoreController_Added_SuperUser + superuser);
}
private void assureSuperUserPasswordIsSet(final Properties properties) {
final boolean unhashedPasswordWasPresent = properties.containsKey(ServerConfiguration.SUPER_USER_PASSWORD);
String password = null;
if (!unhashedPasswordWasPresent) {
if (properties.containsKey(ServerConfiguration.SUPER_USER_PASSWORD_HASH) &&
properties.containsKey(ServerConfiguration.SUPER_USER_PASSWORD_SALT)) {
/* super user password not present but hash and salt -> all is fine */
return;
}
/* no password is available in properties -> get password from user */
final Scanner scanner = new Scanner(System.in);
try {
boolean passwordDidNotMatch = true;
while (passwordDidNotMatch) {
System.out.println(Messages.EMFStoreController_NoSuperUserPasswordPrompt);
final String pw1 = scanner.nextLine();
System.out.println(Messages.EMFStoreController_EnterSuperUserPasswordAgain);
final String pw2 = scanner.nextLine();
if (pw1 != null && pw1.equals(pw2)) {
password = pw1;
passwordDidNotMatch = false;
} else {
System.out.println(Messages.EMFStoreController_PasswordDidNotMatch);
}
}
} finally {
scanner.close();
}
} else {
/* get unhashed password */
password = properties.getProperty(ServerConfiguration.SUPER_USER_PASSWORD);
}
/* migrate non hashed password */
final ESPasswordHashGenerator passwordHashGenerator = AccessControl.getESPasswordHashGenerator();
final File propertyFile = new File(ServerConfiguration.getConfFile());
FileOutputStream propertyFileOutputStream = null;
try {
propertyFileOutputStream = new FileOutputStream(propertyFile);
final ESHashAndSalt hashAndSalt = passwordHashGenerator.hashPassword(password);
properties.setProperty(ServerConfiguration.SUPER_USER_PASSWORD_SALT, hashAndSalt.getSalt());
properties.setProperty(ServerConfiguration.SUPER_USER_PASSWORD_HASH, hashAndSalt.getHash());
properties.remove(ServerConfiguration.SUPER_USER_PASSWORD);
properties.store(propertyFileOutputStream, ""); //$NON-NLS-1$
} catch (final FileNotFoundException ex) {
ModelUtil.logWarning(Messages.EMFStoreController_PasswordHashFailFileNotFound, ex);
} catch (final IOException ex) {
ModelUtil.logWarning(Messages.EMFStoreController_PasswordHashFailIOException, ex);
} finally {
if (propertyFileOutputStream != null) {
try {
propertyFileOutputStream.close();
} catch (final IOException ex) {
ModelUtil.logException(ex);
}
}
}
if (unhashedPasswordWasPresent) {
ServerConfiguration.initUserVerifierMigration();
}
}
private Properties initProperties() {
final File propertyFile = new File(ServerConfiguration.getConfFile());
final Properties properties = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(propertyFile);
properties.load(fis);
ServerConfiguration.setProperties(properties, false);
ModelUtil.logInfo(
MessageFormat.format(Messages.EMFStoreController_PropertyFile_Read, propertyFile.getAbsolutePath()));
} catch (final IOException e) {
ModelUtil.logWarning(Messages.EMFStoreController_Property_Init_Failed, e);
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (final IOException e) {
ModelUtil.logWarning(Messages.EMFStoreController_Closing_Of_Properties_File_Failed, e);
}
}
return properties;
}
/**
* Stops the EMFStore gracefully.
*/
public void stopServer() {
if (instance == null) {
// server already has been stopped manually
return;
}
wakeForTermination();
// connection handlers may be null in case an exception has been thrown
// while starting
if (connectionHandlers != null) {
final Object monitor = MonitorProvider.getInstance().getMonitor();
synchronized (monitor) {
for (final ConnectionHandler<? extends EMFStoreInterface> handler : connectionHandlers) {
handler.stop();
}
}
}
ModelUtil.logInfo(Messages.EMFStoreController_Server_Was_Stopped);
instance = null;
wakeForTermination();
}
/**
* Shutdown EmfStore due to an fatal exception.
*
* @param exception
* the fatal exception that triggered the shutdown
*/
public void shutdown(FatalESException exception) {
ModelUtil.logWarning(Messages.EMFStoreController_Stopping_All_ConnectionHandlers);
if (connectionHandlers != null) {
for (final ConnectionHandler<? extends EMFStoreInterface> handler : connectionHandlers) {
ModelUtil.logWarning(
MessageFormat.format(
Messages.EMFStoreController_Stopping_ConnectionHandler, handler.getName()));
handler.stop();
ModelUtil.logWarning(
MessageFormat.format(
Messages.EMFStoreController_ConnectionHandler_Stopped, handler.getName()));
}
}
ModelUtil.logException(Messages.EMFStoreController_Serve_Forcefully_Stopped, exception);
ModelUtil.logException(Messages.EMFStoreController_Cause_For_Server_Shutdown, exception.getCause());
wakeForTermination();
}
private synchronized void waitForTermination() {
try {
wait();
} catch (final InterruptedException e) {
ModelUtil.logWarning(Messages.EMFStoreController_Waiting_For_Termination_Interrupted, e);
}
}
private synchronized void wakeForTermination() {
notify();
}
private void serverHeader() {
final InputStream inputStream = getClass().getResourceAsStream(EMFSTORE_TXT_FILE);
final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
try {
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (final IOException e) {
// ignore
} finally {
try {
reader.close();
inputStream.close();
} catch (final IOException e) {
// ignore
}
}
}
/**
* {@inheritDoc}
*
* @see java.lang.Runnable#run()
*/
public void run() {
try {
run(false);
} catch (final FatalESException e) {
throw new RuntimeException(e);
}
}
/**
* Starts the server in a new thread.
*
* @return an controller for the running EMFStore
* @throws FatalESException
* in case of failure
*/
public static EMFStoreController runAsNewThread() throws FatalESException {
final EMFStoreController emfStoreController = new EMFStoreController();
final Thread thread = new Thread(emfStoreController);
thread.start();
try {
thread.join();
} catch (final InterruptedException e) {
throw new FatalESException(e);
}
return emfStoreController;
}
/**
* Returns the {@link ServerSpace}.
*
* @return the server space
*/
public ServerSpace getServerSpace() {
return serverSpace;
}
/**
* Returns the {@link AccessControl} component of the EMFStore controller.
*
* @return the {@link AccessControl} component
*/
public AccessControl getAccessControl() {
return accessControl;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
stopServer();
}
}