| /******************************************************************************* |
| * Copyright (c) 2006, 2019 EclipseSource 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: |
| * Innoopract Informationssysteme GmbH - initial API and implementation |
| * EclipseSource - ongoing development |
| * Frank Appel - replaced singletons and static fields (Bug 337787) |
| ******************************************************************************/ |
| package org.eclipse.rap.ui.internal.servlet; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.text.MessageFormat; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.equinox.app.IApplication; |
| import org.eclipse.rap.rwt.application.Application; |
| import org.eclipse.rap.rwt.application.Application.OperationMode; |
| import org.eclipse.rap.rwt.application.ApplicationConfiguration; |
| import org.eclipse.rap.rwt.application.EntryPoint; |
| import org.eclipse.rap.rwt.application.EntryPointFactory; |
| import org.eclipse.rap.rwt.client.WebClient; |
| import org.eclipse.rap.rwt.internal.lifecycle.DefaultEntryPointFactory; |
| import org.eclipse.rap.rwt.service.ResourceLoader; |
| import org.eclipse.rap.rwt.service.ServiceHandler; |
| import org.eclipse.rap.rwt.service.SettingStoreFactory; |
| import org.eclipse.rap.ui.internal.application.EntryPointApplicationWrapper; |
| import org.eclipse.rap.ui.internal.branding.AbstractBranding; |
| import org.eclipse.rap.ui.internal.branding.BrandingExtension; |
| import org.eclipse.rap.ui.internal.branding.BrandingManager; |
| import org.eclipse.rap.ui.internal.branding.BrandingUtil; |
| import org.eclipse.rap.ui.internal.preferences.WorkbenchFileSettingStoreFactory; |
| import org.eclipse.rap.ui.resources.IResource; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.FrameworkUtil; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.service.http.HttpService; |
| |
| |
| public class WorkbenchApplicationConfiguration implements ApplicationConfiguration { |
| |
| private static final String ID_ENTRY_POINT = "org.eclipse.rap.ui.entrypoint"; |
| private static final String ID_THEMES = "org.eclipse.rap.ui.themes"; |
| private static final String ELEMENT_THEME = "theme"; |
| private static final String ELEMENT_THEME_CONTRIBUTION = "themeContribution"; |
| private static final String ID_THEMEABLE_WIDGETS = "org.eclipse.rap.ui.themeableWidgets"; |
| private static final String ID_SERVICE_HANDLER = "org.eclipse.rap.ui.serviceHandler"; |
| private static final String ID_SETTING_STORES = "org.eclipse.rap.ui.settingstores"; |
| |
| private static final String PROP_SETTING_STORES_FACTORY |
| = "org.eclipse.rap.rwt.settingStoreFactory"; |
| |
| private static final String RUN = "run"; //$NON-NLS-1$ |
| private static final String PI_RUNTIME = "org.eclipse.core.runtime"; //$NON-NLS-1$ |
| private static final String PT_APPLICATIONS = "applications"; //$NON-NLS-1$ |
| private static final String PT_APP_VISIBLE = "visible"; //$NON-NLS-1$ |
| |
| private final ServiceReference<HttpService> httpServiceReference; |
| |
| // Default constructor to enable subclassing without adding a dependency to OSGi API |
| public WorkbenchApplicationConfiguration() { |
| httpServiceReference = null; |
| } |
| |
| /* |
| * Note [rst]: public as per request in https://bugs.eclipse.org/bugs/show_bug.cgi?id=372183 |
| */ |
| public WorkbenchApplicationConfiguration( ServiceReference<HttpService> httpServiceReference ) { |
| this.httpServiceReference = httpServiceReference; |
| } |
| |
| @Override |
| public void configure( Application application ) { |
| application.setOperationMode( OperationMode.SWT_COMPATIBILITY ); |
| registerSettingStoreFactory( application ); |
| registerThemeableWidgets( application ); |
| registerThemes( application ); |
| registerThemeContributions( application ); |
| registerResources( application ); |
| registerServiceHandlers( application ); |
| registerBrandings( application ); // [rh] brandings must be red before apps/entry points |
| registerEntryPoints( application ); |
| } |
| |
| private void registerSettingStoreFactory( Application application ) { |
| // determine which factory to use via an environment setting / config.ini |
| SettingStoreFactory result = null; |
| String factoryId = getOSGiProperty( PROP_SETTING_STORES_FACTORY ); |
| if( factoryId != null ) { |
| result = loadSettingStoreFactory( factoryId ); |
| } |
| if( result == null ) { |
| result = new WorkbenchFileSettingStoreFactory(); // default |
| } |
| application.setSettingStoreFactory( result ); |
| } |
| |
| private SettingStoreFactory loadSettingStoreFactory( String factoryId ) { |
| SettingStoreFactory result = null; |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| IExtensionPoint point = registry.getExtensionPoint( ID_SETTING_STORES ); |
| IConfigurationElement[] elements = point.getConfigurationElements(); |
| for( int i = 0; i < elements.length; i++ ) { |
| String id = elements[ i ].getAttribute( "id" ); |
| if( factoryId.equals( id ) ) { |
| result = loadSettingStoreFactory( elements[ i ] ); |
| } |
| } |
| if( result == null ) { |
| String msg = "Unable to find setting store factory with id '" + factoryId + "'."; |
| WorkbenchPlugin.log( msg ); |
| } |
| return result; |
| } |
| |
| private SettingStoreFactory loadSettingStoreFactory( IConfigurationElement element ) { |
| SettingStoreFactory result = null; |
| try { |
| result = ( SettingStoreFactory )element.createExecutableExtension( "class" ); |
| } catch( CoreException cex ) { |
| WorkbenchPlugin.log( cex.getStatus() ); |
| } |
| return result; |
| } |
| |
| private static String getOSGiProperty( String name ) { |
| Bundle bundle = FrameworkUtil.getBundle( WorkbenchApplicationConfiguration.class ); |
| BundleContext bundleContext = bundle.getBundleContext(); |
| Bundle systemBundle = bundleContext.getBundle( Constants.SYSTEM_BUNDLE_ID ); |
| return systemBundle.getBundleContext().getProperty( name ); |
| } |
| |
| @SuppressWarnings( "unchecked" ) |
| private void registerEntryPoints( Application application ) { |
| for( IConfigurationElement element : getEntryPointExtensions() ) { |
| String id = element.getAttribute( "id" ); |
| String path = element.getAttribute( "path" ); |
| String className = element.getAttribute( "class" ); |
| String applicationId = element.getAttribute( "applicationId" ); |
| String brandingId = element.getAttribute( "brandingId" ); |
| try { |
| EntryPointFactory entryPointFactory; |
| if( className != null ) { |
| Class<? extends EntryPoint> entryPointClass = loadClass( className, element ); |
| entryPointFactory = new DefaultEntryPointFactory( entryPointClass ); |
| } else if( applicationId != null ) { |
| entryPointFactory = createEntryPointFactoryForApplication( applicationId ); |
| } else { |
| throw new IllegalArgumentException( "Neither class nor applicationId specified" ); |
| } |
| Map<String, String> properties = getBrandingProperties( brandingId ); |
| application.addEntryPoint( path, entryPointFactory, properties ); |
| } catch( final Throwable thr ) { |
| String text = "Could not register entry point ''{0}'' with id ''{1}''."; |
| Object[] param = new Object[] { className, id }; |
| logProblem( text, param, thr, element.getContributor().getName() ); |
| } |
| } |
| } |
| |
| @SuppressWarnings( "unchecked" ) |
| private EntryPointFactory createEntryPointFactoryForApplication( String applicationId ) |
| throws ClassNotFoundException |
| { |
| IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); |
| String extensionPointId = PI_RUNTIME + '.' + PT_APPLICATIONS; |
| IExtension extension = extensionRegistry.getExtension( extensionPointId, applicationId ); |
| if( extension == null ) { |
| String message = "Application extension not found by id: " + applicationId; |
| throw new IllegalArgumentException( message ); |
| } |
| IConfigurationElement configElement = extension.getConfigurationElements()[ 0 ]; |
| String isVisible = configElement.getAttribute( PT_APP_VISIBLE ); |
| if( isVisible != null && !Boolean.valueOf( isVisible ).booleanValue() ) { |
| throw new IllegalArgumentException( "Application is not visible:" + applicationId ); |
| } |
| IConfigurationElement[] runElement = configElement.getChildren( RUN ); |
| String className = runElement[ 0 ].getAttribute( "class" ); //$NON-NLS-1$ |
| Class<? extends IApplication> applicationClass = loadClass( className, configElement ); |
| return createApplicationEntryPointFactory( applicationClass ); |
| } |
| |
| private static EntryPointFactory |
| createApplicationEntryPointFactory( final Class<? extends IApplication> applicationClass ) |
| { |
| return new EntryPointFactory() { |
| @Override |
| public EntryPoint create() { |
| return new EntryPointApplicationWrapper( applicationClass ); |
| } |
| }; |
| } |
| |
| @SuppressWarnings( "unchecked" ) |
| private void registerThemeableWidgets( Application application ) { |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| IExtensionPoint ep = registry.getExtensionPoint( ID_THEMEABLE_WIDGETS ); |
| IConfigurationElement[] widgetExts = ep.getConfigurationElements(); |
| for( int i = 0; i < widgetExts.length; i++ ) { |
| String contributorName = widgetExts[ i ].getContributor().getName(); |
| String widgetClass = widgetExts[ i ].getAttribute( "class" ); |
| try { |
| final Bundle bundle = Platform.getBundle( contributorName ); |
| Class<? extends Widget> widget = (Class<? extends Widget>)bundle.loadClass( widgetClass ); |
| application.addThemeableWidget( widget ); |
| } catch( final Throwable thr ) { |
| String text = "Could not register themeable widget ''{0}''."; |
| Object[] param = new Object[] { widgetClass }; |
| logProblem( text, param, thr, contributorName ); |
| } |
| } |
| } |
| |
| private void registerThemes( Application application ) { |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| IExtensionPoint ep = registry.getExtensionPoint( ID_THEMES ); |
| IConfigurationElement[] elements = ep.getConfigurationElements(); |
| for( int i = 0; i < elements.length; i++ ) { |
| if( ELEMENT_THEME.equals( elements[ i ].getName() ) ) { |
| String contributorName = elements[ i ].getContributor().getName(); |
| String themeId = elements[ i ].getAttribute( "id" ); |
| String themeFile = elements[ i ].getAttribute( "file" ); |
| try { |
| Bundle bundle = Platform.getBundle( contributorName ); |
| ResourceLoader resourceLoader = createThemeResourceLoader( bundle ); |
| application.addStyleSheet( themeId, themeFile, resourceLoader ); |
| } catch( final Exception e ) { |
| String text = "Could not register custom theme ''{0}'' from file ''{1}''."; |
| Object[] param = new Object[] { themeId, themeFile }; |
| logProblem( text, param, e, contributorName ); |
| } |
| } |
| } |
| } |
| |
| private void registerThemeContributions( Application application ) { |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| IExtensionPoint ep = registry.getExtensionPoint( ID_THEMES ); |
| IConfigurationElement[] elements = ep.getConfigurationElements(); |
| for( int i = 0; i < elements.length; i++ ) { |
| if( ELEMENT_THEME_CONTRIBUTION.equals( elements[ i ].getName() ) ) { |
| String contributorName = elements[ i ].getContributor().getName(); |
| String themeId = elements[ i ].getAttribute( "themeId" ); |
| String themeFile = elements[ i ].getAttribute( "file" ); |
| try { |
| Bundle bundle = Platform.getBundle( contributorName ); |
| ResourceLoader loader = createThemeResourceLoader( bundle ); |
| application.addStyleSheet( themeId, themeFile, loader ); |
| } catch( final Exception e ) { |
| String text = "Could not register contribution for theme ''{0}'' from file ''{1}''."; |
| Object[] param = new Object[] { themeId, themeFile }; |
| logProblem( text, param, e, contributorName ); |
| } |
| } |
| } |
| } |
| |
| private static void registerResources( Application application ) { |
| List<IResource> resources = ResourceReader.readResources(); |
| new ResourceRegisterer( application ).registerResources( resources ); |
| } |
| |
| private static ResourceLoader createThemeResourceLoader( final Bundle bundle ) { |
| ResourceLoader result = new ResourceLoader() { |
| @Override |
| public InputStream getResourceAsStream( final String resourceName ) throws IOException { |
| InputStream result = null; |
| IPath path = new Path( resourceName ); |
| URL url = FileLocator.find( bundle, path, null ); |
| if( url != null ) { |
| result = url.openStream(); |
| } |
| return result; |
| } |
| }; |
| return result; |
| } |
| |
| private void registerServiceHandlers( Application application ) { |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| IExtensionPoint point = registry.getExtensionPoint( ID_SERVICE_HANDLER ); |
| IConfigurationElement[] elements = point.getConfigurationElements(); |
| for( int i = 0; i < elements.length; i++ ) { |
| try { |
| String id = elements[ i ].getAttribute( "id" ); |
| if( id != null ) { |
| Object extObject = elements[ i ].createExecutableExtension( "class" ); |
| ServiceHandler handler = ( ServiceHandler )extObject; |
| application.addServiceHandler( id, handler ); |
| } |
| } catch( final CoreException ce ) { |
| WorkbenchPlugin.getDefault().getLog().log( ce.getStatus() ); |
| } |
| } |
| } |
| |
| private void registerBrandings( Application application ) { |
| try { |
| new BrandingExtension( application, httpServiceReference ).read(); |
| } catch( final IOException ioe ) { |
| throw new RuntimeException( "Unable to read branding extension", ioe ); |
| } |
| } |
| |
| private static AbstractBranding findBrandingById( String id ) { |
| AbstractBranding result = null; |
| AbstractBranding[] brandings = BrandingManager.getInstance().getAll(); |
| for( AbstractBranding branding : brandings ) { |
| if( branding.getId() != null && branding.getId().equals( id ) ) { |
| result = branding; |
| } |
| } |
| return result; |
| } |
| |
| private Map<String, String> getBrandingProperties( String brandingId ) { |
| AbstractBranding branding = findBrandingById( brandingId ); |
| Map<String, String> result = new HashMap<String, String>(); |
| result.put( BrandingUtil.ENTRY_POINT_BRANDING, brandingId ); |
| if( branding != null ) { |
| result.put( WebClient.THEME_ID, branding.getThemeId() ); |
| result.put( WebClient.BODY_HTML, branding.getBody() ); |
| result.put( WebClient.PAGE_TITLE, branding.getTitle() ); |
| result.put( WebClient.FAVICON, branding.getFavIcon() ); |
| result.put( WebClient.HEAD_HTML, BrandingUtil.headerMarkup( branding ) ); |
| } |
| return result; |
| } |
| |
| private static IConfigurationElement[] getEntryPointExtensions() { |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| IExtensionPoint extensionPoint = registry.getExtensionPoint( ID_ENTRY_POINT ); |
| IConfigurationElement[] elements = extensionPoint.getConfigurationElements(); |
| return elements; |
| } |
| |
| private static void logProblem( String text, |
| Object[] textParams, |
| Throwable problem, |
| String bundleId ) |
| { |
| String msg = MessageFormat.format( text, textParams ); |
| Status status = new Status( IStatus.ERROR, bundleId, IStatus.OK, msg, problem ); |
| WorkbenchPlugin.getDefault().getLog().log( status ); |
| } |
| |
| private static <T> T loadClass( String className, IConfigurationElement element ) |
| throws ClassNotFoundException |
| { |
| Bundle bundle = Platform.getBundle( element.getContributor().getName() ); |
| return ( T )bundle.loadClass( className ); |
| } |
| |
| } |