Package at.bestsolution.efxclipse.runtime.workbench.fx

Source Code of at.bestsolution.efxclipse.runtime.workbench.fx.E4Application

/*******************************************************************************
* Copyright (c) 2012 BestSolution.at 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:
*     Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
*******************************************************************************/
package at.bestsolution.efxclipse.runtime.workbench.fx;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
import java.util.Properties;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;

import javafx.application.Application;
import javafx.scene.image.Image;
import javafx.stage.Stage;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.internal.services.EclipseAdapter;
import org.eclipse.e4.core.services.adapter.Adapter;
import org.eclipse.e4.core.services.contributions.IContributionFactory;
import org.eclipse.e4.core.services.log.ILoggerProvider;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.core.services.translation.TranslationProviderFactory;
import org.eclipse.e4.core.services.translation.TranslationService;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.e4.ui.internal.workbench.ActiveChildLookupFunction;
import org.eclipse.e4.ui.internal.workbench.ActivePartLookupFunction;
import org.eclipse.e4.ui.internal.workbench.E4Workbench;
import org.eclipse.e4.ui.internal.workbench.ExceptionHandler;
import org.eclipse.e4.ui.internal.workbench.ModelServiceImpl;
import org.eclipse.e4.ui.internal.workbench.PlaceholderResolver;
import org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory;
import org.eclipse.e4.ui.internal.workbench.ResourceHandler;
import org.eclipse.e4.ui.model.application.MAddon;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.e4.ui.workbench.IExceptionHandler;
import org.eclipse.e4.ui.workbench.IModelResourceHandler;
import org.eclipse.e4.ui.workbench.IResourceUtilities;
import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate;
import org.eclipse.e4.ui.workbench.lifecycle.PreSave;
import org.eclipse.e4.ui.workbench.lifecycle.ProcessAdditions;
import org.eclipse.e4.ui.workbench.lifecycle.ProcessRemovals;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPlaceholderResolver;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.osgi.service.datalocation.Location;

import at.bestsolution.efxclipse.runtime.application.AbstractJFXApplication;
import at.bestsolution.efxclipse.runtime.osgi.util.LoggerCreator;
import at.bestsolution.efxclipse.runtime.workbench.fx.internal.LoggerProviderImpl;
import at.bestsolution.efxclipse.runtime.workbench.fx.internal.WorkbenchJFXActivator;

@SuppressWarnings("restriction")
public class E4Application extends AbstractJFXApplication {
  public static final String THEME_ID = "cssTheme";

  public static final String METADATA_FOLDER = ".metadata"; //$NON-NLS-1$
  private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$
  private static final String WORKSPACE_VERSION_KEY = "org.eclipse.core.runtime"; //$NON-NLS-1$
  private static final String WORKSPACE_VERSION_VALUE = "2"; //$NON-NLS-1$
  private static final String EXIT_CODE = "e4.osgi.exit.code";
 
  private String[] args;
  private Object lcManager;
  private E4Workbench workbench = null;
  private IModelResourceHandler handler;

  private IEclipseContext workbenchContext;

  private Location instanceLocation;

  at.bestsolution.efxclipse.runtime.core.log.Logger logger = LoggerCreator.createLogger(getClass());
 
  @Override
  protected void jfxStart(IApplicationContext applicationContext, Application jfxApplication, Stage primaryStage) {
    workbench = createE4Workbench(applicationContext, jfxApplication, primaryStage);
    if( workbench != null ) {
      instanceLocation = (Location) workbench.getContext().get(E4Workbench.INSTANCE_LOCATION);

      try {
        if (!checkInstanceLocation(instanceLocation))
          return;

        workbenchContext = workbench.getContext();

        // Create and run the UI (if any)
        workbench.createAndRunUI(workbench.getApplication());

        return;
      } finally {
       
      }
    }
  }

  @Override
  protected Object jfxStop() {
    Object returnCode = null;
    try {
      if( workbenchContext != null && workbench != null ) {
        returnCode = workbenchContext.get(EXIT_CODE);
        // Save the model into the targetURI
        if (lcManager != null) {
          ContextInjectionFactory.invoke(lcManager, PreSave.class, workbenchContext, null);
        }
        saveModel();
        workbench.close()
      }
    } finally {
      if (instanceLocation != null)
        instanceLocation.release();
    }
   
    if( returnCode != null ) {
      return returnCode;
    } else {
      return super.jfxStop()
    }
  }

  public E4Workbench createE4Workbench(IApplicationContext applicationContext, Application jfxApplication, Stage primaryStage) {
    args = (String[]) applicationContext.getArguments().get(IApplicationContext.APPLICATION_ARGS);

    IEclipseContext appContext = createDefaultContext();
   
    //FIXME We need to fix this later on see ticket 256
//    ContextInjectionFactory.setDefault(appContext);
    try {
      Method m = ContextInjectionFactory.class.getMethod("setDefault", IEclipseContext.class);
      m.invoke(null, appContext);
    } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
      System.err.println("WARNING: You are running on an old and buggy DI container which is fixed in 4.2.2 builds. Consider upgradeing.");
    }
   

   
    appContext.set(Application.class, jfxApplication);
    appContext.set("primaryStage", primaryStage);
    // appContext.set(Realm.class, SWTObservables.getRealm(display));
    appContext.set(UISynchronize.class, new UISynchronize() {

      public void syncExec(final Runnable runnable) {
        if (javafx.application.Platform.isFxApplicationThread()) {
          runnable.run();
        } else {
          RunnableFuture<?> task = new FutureTask<Void>(runnable, null);
         
          javafx.application.Platform.runLater(task);

          try {
            // wait for task to complete
            task.get();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          } finally {
            task.cancel(true);
          }
        }
      }

      public void asyncExec(Runnable runnable) {
        javafx.application.Platform.runLater(runnable);
      }
    });
    appContext.set(IApplicationContext.class, applicationContext);
    appContext.set(IResourceUtilities.class, new IResourceUtilities<Image>() {
      private WeakHashMap<URI, WeakReference<Image>> imageCache = new WeakHashMap<URI, WeakReference<Image>>();
     
      public Image imageDescriptorFromURI(URI iconPath) {
        WeakReference<Image> r = imageCache.get(iconPath);
        Image img = null;
        if( r != null ) {
          img = r.get();
        }
       
        if( img == null ) {
          try {
            InputStream in = new URL(iconPath.toString()).openStream();
            img = new Image(in);
            in.close();
            imageCache.put(iconPath, new WeakReference<Image>(img));
          } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          } catch (IOException e) {
            logger.warning("could not find icon at: " + iconPath,e);
          }
        }
       
        return img;
      }
    });

    // Check if DS is running
    if (!appContext.containsKey("org.eclipse.e4.ui.workbench.modeling.EModelService")) {
      throw new IllegalStateException("Core services not available. Please make sure that a declarative service implementation (such as the bundle 'org.eclipse.equinox.ds') is available!");
    }

    // Get the factory to create DI instances with
    IContributionFactory factory = (IContributionFactory) appContext.get(IContributionFactory.class.getName());

    // Install the life-cycle manager for this session if there's one
    // defined
    String lifeCycleURI = getArgValue(E4Workbench.LIFE_CYCLE_URI_ARG, applicationContext, false);
    if (lifeCycleURI != null) {
      lcManager = factory.create(lifeCycleURI, appContext);
      if (lcManager != null) {
        // Let the manager manipulate the appContext if desired
        Boolean rv = (Boolean) ContextInjectionFactory.invoke(lcManager, PostContextCreate.class, appContext, Boolean.TRUE);
        if( rv != null && ! rv.booleanValue() ) {
          return null;
        }
      }
    }
    // Create the app model and its context
    MApplication appModel = loadApplicationModel(applicationContext, appContext);
    appModel.setContext(appContext);

    // Set the app's context after adding itself
    appContext.set(MApplication.class.getName(), appModel);

    // let the life cycle manager add to the model
    if (lcManager != null) {
      ContextInjectionFactory.invoke(lcManager, ProcessAdditions.class, appContext, null);
      ContextInjectionFactory.invoke(lcManager, ProcessRemovals.class, appContext, null);
    }

    // Create the addons
    IEclipseContext addonStaticContext = EclipseContextFactory.create();
    for (MAddon addon : appModel.getAddons()) {
      addonStaticContext.set(MAddon.class, addon);
      Object obj = factory.create(addon.getContributionURI(), appContext, addonStaticContext);
      addon.setObject(obj);
    }

    // Parse out parameters from both the command line and/or the product
    // definition (if any) and put them in the context
    String xmiURI = getArgValue(E4Workbench.XMI_URI_ARG, applicationContext, false);
    appContext.set(E4Workbench.XMI_URI_ARG, xmiURI);

    String themeId = getArgValue(E4Application.THEME_ID, applicationContext, false);
    appContext.set(E4Application.THEME_ID, themeId);
    appContext.set(E4Workbench.RENDERER_FACTORY_URI, getArgValue(E4Workbench.RENDERER_FACTORY_URI, applicationContext, false));

    // This is a default arg, if missing we use the default rendering engine
    String presentationURI = getArgValue(E4Workbench.PRESENTATION_URI_ARG, applicationContext, false);
    if (presentationURI == null) {
      presentationURI = PartRenderingEngine.engineURI;
    }
    appContext.set(E4Workbench.PRESENTATION_URI_ARG, presentationURI);

    // Instantiate the Workbench (which is responsible for
    // 'running' the UI (if any)...
    return workbench = new E4Workbench(appModel, appContext);
  }

  private MApplication loadApplicationModel(IApplicationContext appContext, IEclipseContext eclipseContext) {
    MApplication theApp = null;

    Location instanceLocation = WorkbenchJFXActivator.getDefault().getInstanceLocation();

    String appModelPath = getArgValue(E4Workbench.XMI_URI_ARG, appContext, false);
    Assert.isNotNull(appModelPath, E4Workbench.XMI_URI_ARG + " argument missing"); //$NON-NLS-1$
    final URI initialWorkbenchDefinitionInstance = URI.createPlatformPluginURI(appModelPath, true);

    eclipseContext.set(E4Workbench.INITIAL_WORKBENCH_MODEL_URI, initialWorkbenchDefinitionInstance);
    eclipseContext.set(E4Workbench.INSTANCE_LOCATION, instanceLocation);

    // Save and restore
    boolean saveAndRestore;
    String value = getArgValue(E4Workbench.PERSIST_STATE, appContext, false);

    saveAndRestore = value == null || Boolean.parseBoolean(value);

    eclipseContext.set(E4Workbench.PERSIST_STATE, Boolean.valueOf(saveAndRestore));

    // Persisted state
    boolean clearPersistedState;
    value = getArgValue(E4Workbench.CLEAR_PERSISTED_STATE, appContext, true);
    clearPersistedState = value != null && Boolean.parseBoolean(value);
    eclipseContext.set(E4Workbench.CLEAR_PERSISTED_STATE, Boolean.valueOf(clearPersistedState));

    // Delta save and restore
    boolean deltaRestore;
    value = getArgValue(E4Workbench.DELTA_RESTORE, appContext, false);
    deltaRestore = value == null || Boolean.parseBoolean(value);
    eclipseContext.set(E4Workbench.DELTA_RESTORE, Boolean.valueOf(deltaRestore));

    String resourceHandler = getArgValue(E4Workbench.MODEL_RESOURCE_HANDLER, appContext, false);

    if (resourceHandler == null) {
      resourceHandler = "bundleclass://org.eclipse.e4.ui.workbench/" + ResourceHandler.class.getName();
    }

    IContributionFactory factory = eclipseContext.get(IContributionFactory.class);

    handler = (IModelResourceHandler) factory.create(resourceHandler, eclipseContext);

    Resource resource = handler.loadMostRecentModel();
    theApp = (MApplication) resource.getContents().get(0);

    return theApp;
  }
 
  private String getArgValue(String argName, IApplicationContext appContext, boolean singledCmdArgValue) {
    // Is it in the arg list ?
    if (argName == null || argName.length() == 0)
      return null;

    if (singledCmdArgValue) {
      for (int i = 0; i < args.length; i++) {
        if (("-" + argName).equals(args[i]))
          return "true";
      }
    } else {
      for (int i = 0; i < args.length; i++) {
        if (("-" + argName).equals(args[i]) && i + 1 < args.length)
          return args[i + 1];
      }
    }

    final String brandingProperty = appContext.getBrandingProperty(argName);
    return brandingProperty == null ? System.getProperty(argName) : brandingProperty;
  }

  // TODO This should go into a different bundle
  public static IEclipseContext createDefaultHeadlessContext() {
      IEclipseContext serviceContext = E4Workbench.getServiceContext();

      IExtensionRegistry registry = RegistryFactory.getRegistry();
      ExceptionHandler exceptionHandler = new ExceptionHandler();
      ReflectionContributionFactory contributionFactory = new ReflectionContributionFactory(
          registry);
      serviceContext.set(IContributionFactory.class, contributionFactory);
      serviceContext.set(IExceptionHandler.class, exceptionHandler);
      serviceContext.set(IExtensionRegistry.class, registry);

      // translation
      String locale = Locale.getDefault().toString();
      serviceContext.set(TranslationService.LOCALE, locale);
      TranslationService bundleTranslationProvider = TranslationProviderFactory
          .bundleTranslationService(serviceContext);
      serviceContext.set(TranslationService.class, bundleTranslationProvider);

      serviceContext.set(Adapter.class, ContextInjectionFactory.make(
          EclipseAdapter.class, serviceContext));

      // No default log provider available
      if (serviceContext.get(ILoggerProvider.class) == null) {
        serviceContext.set(ILoggerProvider.class, ContextInjectionFactory.make(LoggerProviderImpl.class, serviceContext));
      }

      return serviceContext;
  }

  public static IEclipseContext createDefaultContext() {
    IEclipseContext serviceContext = E4Workbench.getServiceContext();
    final IEclipseContext appContext = serviceContext.createChild("WorkbenchContext");
    IExtensionRegistry registry = RegistryFactory.getRegistry();
    ExceptionHandler exceptionHandler = new ExceptionHandler();
    ReflectionContributionFactory contributionFactory = new ReflectionContributionFactory(registry);
    appContext.set(IContributionFactory.class.getName(), contributionFactory);

    // No default log provider available
    if (appContext.get(ILoggerProvider.class) == null) {
      serviceContext.set(ILoggerProvider.class, ContextInjectionFactory.make(LoggerProviderImpl.class, serviceContext));
    }
   
    appContext.set(Logger.class.getName(), serviceContext.get(ILoggerProvider.class).getClassLogger(E4Workbench.class));

    appContext.set(EModelService.class, new ModelServiceImpl(appContext));
    appContext.set(EPlaceholderResolver.class, new PlaceholderResolver());

    // translation
    String locale = Locale.getDefault().toString();
    appContext.set(TranslationService.LOCALE, locale);
    TranslationService bundleTranslationProvider = TranslationProviderFactory.bundleTranslationService(appContext);
    appContext.set(TranslationService.class, bundleTranslationProvider);

    appContext.set(Adapter.class.getName(), ContextInjectionFactory.make(EclipseAdapter.class, appContext));


    appContext.set(IServiceConstants.ACTIVE_PART, new ActivePartLookupFunction());
    appContext.set(IExceptionHandler.class.getName(), exceptionHandler);
    appContext.set(IExtensionRegistry.class.getName(), registry);

    appContext.set(IServiceConstants.ACTIVE_SHELL, new ActiveChildLookupFunction(IServiceConstants.ACTIVE_SHELL, E4Workbench.LOCAL_ACTIVE_SHELL));

    appContext.set(IExtensionRegistry.class.getName(), registry);
    appContext.set(IContributionFactory.class.getName(), contributionFactory);

    return appContext;
  }

  private boolean checkInstanceLocation(Location instanceLocation) {
    if (instanceLocation == null) {
      // MessageDialog
      // .openError(
      // shell,
      // WorkbenchSWTMessages.IDEApplication_workspaceMandatoryTitle,
      // WorkbenchSWTMessages.IDEApplication_workspaceMandatoryMessage);
      return false;
    }

    // -data "/valid/path", workspace already set
    if (instanceLocation.isSet()) {
      // make sure the meta data version is compatible (or the user has
      // chosen to overwrite it).
      if (!checkValidWorkspace(instanceLocation.getURL())) {
        return false;
      }

      // at this point its valid, so try to lock it and update the
      // metadata version information if successful
      try {
        if (instanceLocation.lock()) {
          writeWorkspaceVersion();
          return true;
        }

        // we failed to create the directory.
        // Two possibilities:
        // 1. directory is already in use
        // 2. directory could not be created
        File workspaceDirectory = new File(instanceLocation.getURL().getFile());
        if (workspaceDirectory.exists()) {
          // MessageDialog
          // .openError(
          // shell,
          // WorkbenchSWTMessages.IDEApplication_workspaceCannotLockTitle,
          // WorkbenchSWTMessages.IDEApplication_workspaceCannotLockMessage);
        } else {
          // MessageDialog
          // .openError(
          // shell,
          // WorkbenchSWTMessages.IDEApplication_workspaceCannotBeSetTitle,
          // WorkbenchSWTMessages.IDEApplication_workspaceCannotBeSetMessage);
        }
      } catch (IOException e) {
        logger.error("Could not create instance location", e);
        // MessageDialog.openError(shell,
        // WorkbenchSWTMessages.InternalError, e.getMessage());
      }
      return false;
    }

    return false;
  }

  private boolean checkValidWorkspace(URL url) {
    // a null url is not a valid workspace
    if (url == null) {
      return false;
    }

    String version = readWorkspaceVersion(url);

    // if the version could not be read, then there is not any existing
    // workspace data to trample, e.g., perhaps its a new directory that
    // is just starting to be used as a workspace
    if (version == null) {
      return true;
    }

    final int ide_version = Integer.parseInt(WORKSPACE_VERSION_VALUE);
    int workspace_version = Integer.parseInt(version);

    // equality test is required since any version difference (newer
    // or older) may result in data being trampled
    if (workspace_version == ide_version) {
      return true;
    }

    // At this point workspace has been detected to be from a version
    // other than the current ide version -- find out if the user wants
    // to use it anyhow.
    // String title = WorkbenchSWTMessages.IDEApplication_versionTitle;
    // String message = NLS.bind(
    // WorkbenchSWTMessages.IDEApplication_versionMessage,
    // url.getFile());
    //
    // MessageBox mbox = new MessageBox(shell, SWT.OK | SWT.CANCEL
    // | SWT.ICON_WARNING | SWT.APPLICATION_MODAL);
    // mbox.setText(title);
    // mbox.setMessage(message);
    // return mbox.open() == SWT.OK;
    return true;
  }

  private static String readWorkspaceVersion(URL workspace) {
    File versionFile = getVersionFile(workspace, false);
    if (versionFile == null || !versionFile.exists()) {
      return null;
    }

    try {
      // Although the version file is not spec'ed to be a Java properties
      // file, it happens to follow the same format currently, so using
      // Properties to read it is convenient.
      Properties props = new Properties();
      FileInputStream is = new FileInputStream(versionFile);
      try {
        props.load(is);
      } finally {
        is.close();
      }

      return props.getProperty(WORKSPACE_VERSION_KEY);
    } catch (IOException e) {
      LoggerCreator.createLogger(E4Application.class).error("Unable to create workspace", e);
      return null;
    }
  }

  private static File getVersionFile(URL workspaceUrl, boolean create) {
    if (workspaceUrl == null) {
      return null;
    }

    try {
      // make sure the directory exists
      File metaDir = new File(workspaceUrl.getPath(), METADATA_FOLDER);
      if (!metaDir.exists() && (!create || !metaDir.mkdir())) {
        return null;
      }

      // make sure the file exists
      File versionFile = new File(metaDir, VERSION_FILENAME);
      if (!versionFile.exists() && (!create || !versionFile.createNewFile())) {
        return null;
      }

      return versionFile;
    } catch (IOException e) {
      // cannot log because instance area has not been set
      return null;
    }
  }

  private static void writeWorkspaceVersion() {
    Location instanceLoc = Platform.getInstanceLocation();
    if (instanceLoc == null || instanceLoc.isReadOnly()) {
      return;
    }

    File versionFile = getVersionFile(instanceLoc.getURL(), true);
    if (versionFile == null) {
      return;
    }

    OutputStream output = null;
    try {
      String versionLine = WORKSPACE_VERSION_KEY + '=' + WORKSPACE_VERSION_VALUE;

      output = new FileOutputStream(versionFile);
      output.write(versionLine.getBytes("UTF-8")); //$NON-NLS-1$
    } catch (IOException e) {
      LoggerCreator.createLogger(E4Application.class).error("Unable to write workspace version", e);
    } finally {
      try {
        if (output != null) {
          output.close();
        }
      } catch (IOException e) {
        // do nothing
      }
    }
  }

  public void saveModel() {
    try {
      handler.save();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
TOP

Related Classes of at.bestsolution.efxclipse.runtime.workbench.fx.E4Application

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.