/*******************************************************************************
* Copyright (c) 2009, 2016 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.internal.server.core;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.orion.internal.server.core.metastore.SimpleMetaStore;
import org.eclipse.orion.internal.server.core.tasks.TaskService;
import org.eclipse.orion.internal.server.core.workspacepruner.WorkspacePrunerJob;
import org.eclipse.orion.server.core.LogHelper;
import org.eclipse.orion.server.core.OrionConfiguration;
import org.eclipse.orion.server.core.PreferenceHelper;
import org.eclipse.orion.server.core.ServerConstants;
import org.eclipse.orion.server.core.metastore.IMetaStore;
import org.eclipse.orion.server.core.tasks.ITaskService;
import org.eclipse.osgi.service.datalocation.Location;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Activator for the server core bundle.
*/
public class Activator implements BundleActivator {
private static volatile BundleContext bundleContext;
private static Activator singleton;
private ServiceTracker<IPreferencesService, IPreferencesService> prefTracker;
private ServiceRegistration<ITaskService> taskServiceRegistration;
private ITaskService taskService;
private IMetaStore metastore;
private URI rootStoreURI;
private WorkspacePrunerJob workspacePrunerJob;
private static final Logger logger = LoggerFactory.getLogger(LogHelper.LOGGER_ID);
private ServiceTracker<Location, Location> instanceLocationTracker;
public static final String PI_SERVER_CORE = "org.eclipse.orion.server.core"; //$NON-NLS-1$
public static Activator getDefault() {
return singleton;
}
/**
* Returns the currently configured metadata store for this server. This method never returns <code>null</code>.
*
* @throws IllegalStateException
* if the server is not properly configured to have an @link {@link IMetaStore}.
*/
public synchronized IMetaStore getMetastore() {
return metastore;
}
/**
* Returns the preference service, or <code>null</code> if not available.
*/
public static IPreferencesService getPreferenceService() {
// protect against concurrent shutdown
Activator a = singleton;
if (a == null)
return null;
ServiceTracker<IPreferencesService, IPreferencesService> tracker = a.getPrefTracker();
if (tracker == null)
return null;
return tracker.getService();
}
public ITaskService getTaskService() {
return taskService;
}
public BundleContext getContext() {
return bundleContext;
}
private ServiceTracker<IPreferencesService, IPreferencesService> getPrefTracker() {
if (prefTracker != null)
return prefTracker;
// lazy init if the bundle has been started
if (bundleContext == null)
return null;
prefTracker = new ServiceTracker<IPreferencesService, IPreferencesService>(bundleContext, IPreferencesService.class, null);
prefTracker.open();
return prefTracker;
}
/**
* Returns the root file system location for storing task data. Never returns null.
*
* @throws IOException
*/
private IPath getTaskLocation() throws IOException {
// Make sure the registry is started so the preferences work correctly.
// Lots of bundles access the file system location, and some of them start early
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=439716#c10
ensureBundleStarted("org.eclipse.equinox.registry"); // $NON-NLS-1$
String locationPref = PreferenceHelper.getString(ServerConstants.CONFIG_FILE_TASKS);
if (locationPref != null) {
return new Path(locationPref);
}
return getPlatformLocation().append(".metadata/.tasks"); // $NON-NLS-1$
}
private void initializeMetaStore() {
try {
metastore = new SimpleMetaStore(OrionConfiguration.getRootLocation().toLocalFile(EFS.NONE, null));
} catch (CoreException e) {
String msg = "Cannot initialize MetaStore";
logger.error(msg, e);
throw new RuntimeException(msg, e); // $NON-NLS-1$
}
bundleContext.registerService(IMetaStore.class, metastore, null);
}
@Override
public void start(BundleContext context) throws Exception {
singleton = this;
bundleContext = context;
registerServices();
initializeFileSystem();
initializeMetaStore();
startWorkspacePrunerJob();
logger.info("Started Orion server core successfully."); //$NON-NLS-1$
}
private void startWorkspacePrunerJob() {
String workspacePruningEnabled = PreferenceHelper.getString(ServerConstants.CONFIG_WORKSPACEPRUNER_ENABLED, "false").toLowerCase(); //$NON-NLS-1$
if ("true".equals(workspacePruningEnabled)) { //$NON-NLS-1$
workspacePrunerJob = new WorkspacePrunerJob();
/* start the pruning job in one minute */
workspacePrunerJob.schedule(60000);
}
}
private void registerServices() {
try {
IPath taskLocation = getTaskLocation();
taskService = new TaskService(taskLocation);
taskServiceRegistration = bundleContext.registerService(ITaskService.class, taskService, null);
} catch (IOException e) {
LogHelper.log(new Status(IStatus.ERROR, ServerConstants.PI_SERVER_CORE, "Failed to initialize task service", e)); //$NON-NLS-1$
}
}
@Override
public void stop(BundleContext context) throws Exception {
metastore = null;
stopTaskService();
if (prefTracker != null) {
prefTracker.close();
prefTracker = null;
}
bundleContext = null;
}
/**
* Returns the root file system location the OSGi instance area.
*/
public IPath getPlatformLocation() {
BundleContext context = Activator.getDefault().getContext();
Collection<ServiceReference<Location>> refs;
try {
refs = context.getServiceReferences(Location.class, Location.INSTANCE_FILTER);
} catch (InvalidSyntaxException e) {
// we know the instance location filter syntax is valid
throw new RuntimeException(e);
}
if (refs.isEmpty())
return null;
ServiceReference<Location> ref = refs.iterator().next();
Location location = context.getService(ref);
try {
if (location == null)
return null;
URL root = location.getURL();
if (root == null)
return null;
// strip off file: prefix from URL
return new Path(root.toExternalForm().substring(5));
} finally {
context.ungetService(ref);
}
}
private void initializeFileSystem() {
IPath location = getFileSystemLocation();
if (location == null) {
RuntimeException e = new RuntimeException("Unable to compute base file system location");
logger.error("Failed to initialize server file system", e);
throw e; // $NON-NLS-1$
}
IFileStore rootStore = EFS.getLocalFileSystem().getStore(location);
try {
rootStore.mkdir(EFS.NONE, null);
rootStoreURI = rootStore.toURI();
} catch (CoreException e) {
String msg = "Instance location is read only: " + rootStore;
logger.error(msg, e);
throw new RuntimeException(msg, e); // $NON-NLS-1$
}
}
private IPath getFileSystemLocation() {
// Make sure the registry is started so the preferences work correctly.
// Lots of bundles access the file system location, and some of them start early
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=439716#c10
ensureBundleStarted("org.eclipse.equinox.registry");
String locationPref = PreferenceHelper.getString(ServerConstants.CONFIG_FILE_USER_CONTENT);
if (locationPref != null) {
return new Path(locationPref);
}
return getPlatformLocation();
}
private void stopTaskService() {
ServiceRegistration<ITaskService> reg = taskServiceRegistration;
taskServiceRegistration = null;
taskService = null;
if (reg != null)
reg.unregister();
}
/**
* Returns the root location for storing content and metadata on this server.
*/
public URI getRootLocationURI() {
return rootStoreURI;
}
private void ensureBundleStarted(String symbolicName) {
Bundle bundle = getBundle(symbolicName);
if (bundle != null) {
if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.STARTING) {
try {
bundle.start(Bundle.START_TRANSIENT);
} catch (BundleException e) {
Logger logger = LoggerFactory.getLogger("org.eclipse.orion.server.core"); //$NON-NLS-1$
logger.error("Could not start bundle " + symbolicName, e);
}
}
}
}
private Bundle getBundle(String symbolicName) {
for (Bundle bundle : getContext().getBundles()) {
if (symbolicName.equals(bundle.getSymbolicName())) {
return bundle;
}
}
return null;
}
Location getInstanceLocation() {
if (instanceLocationTracker == null) {
Filter filter;
try {
filter = bundleContext.createFilter(Location.INSTANCE_FILTER);
} catch (InvalidSyntaxException e) {
LogHelper.log(e);
return null;
}
instanceLocationTracker = new ServiceTracker<Location, Location>(bundleContext, filter, null);
instanceLocationTracker.open();
}
return instanceLocationTracker.getService();
}
String getProperty(String key) {
return bundleContext.getProperty(key);
}
}