/****************************************************************************** * Copyright (c) 2009-2013, Linagora * * 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: * Linagora - initial API and implementation *******************************************************************************/ package com.ebmwebsourcing.petals.services.explorer; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchListener; import org.eclipse.ui.PlatformUI; import com.ebmwebsourcing.petals.services.PetalsServicesPlugin; import com.ebmwebsourcing.petals.services.explorer.sources.CurrentWorkspaceSource; import com.ebmwebsourcing.petals.services.explorer.sources.EndpointSource; import com.ebmwebsourcing.petals.services.explorer.sources.ExternalWorkspaceSource; import com.ebmwebsourcing.petals.services.explorer.sources.SaDirectorySource; import com.ebmwebsourcing.petals.services.utils.ServiceProjectRelationUtils; /** * The class in charge of managing all the end-point sources. * <p> * When a source must be added, removed, or is changed, it must be signaled * in this class. The changes will be propagated to listeners. * </p> * * @author Vincent Zurczak - EBM WebSourcing */ public class SourceManager implements IResourceChangeListener { private static final String EXT_WK_SRC_PREF = "petals.service-explorer.external-workspaces"; private static final String SA_FLDR_SRC_PREF = "petals.service-explorer.sa-folders"; private static SourceManager instance = new SourceManager (); private final Set<EndpointSource> sources = new HashSet<EndpointSource> (); private final List<ISourceChangeListener> listeners = new ArrayList<ISourceChangeListener> (); private final CurrentWorkspaceSource currentWorkspaceSource = new CurrentWorkspaceSource(); private boolean restoredSources = false; /** * Constructor. */ private SourceManager() { // Listen to the workbench ResourcesPlugin.getWorkspace().addResourceChangeListener( this, IResourceChangeEvent.POST_BUILD ); // Listen to the workbench // Release resources when the workbench is closed PlatformUI.getWorkbench().addWorkbenchListener( new IWorkbenchListener() { @Override public boolean preShutdown( IWorkbench workbench, boolean forced ) { // Do not be notified by workspace changes anymore ResourcesPlugin.getWorkspace().removeResourceChangeListener( SourceManager.this ); // Dispose remaining sources for( EndpointSource source : SourceManager.this.sources ) source.dispose(); return true; } @Override public void postShutdown( IWorkbench workbench ) { // nothing } }); } /** * @return */ public static SourceManager getInstance() { return instance; } /** * Returns the list of end-point sources. * <p> * If sources were stored and not yet restored, they are restored. * </p> * * @return the sources */ public Collection<EndpointSource> getSources() { if( ! this.restoredSources ) { restoreSavedSources(); this.restoredSources = true; } return Collections.unmodifiableSet( this.sources ); } /** * @param source * @return * @see java.util.List#add(java.lang.Object) */ public boolean addSource( EndpointSource source ) { boolean result = this.sources.add( source ); for( ISourceChangeListener listener : this.listeners ) listener.sourceAdded( source ); storeSources(); return result; } /** * @param source * @return * @see java.util.List#remove(java.lang.Object) */ public boolean removeSource( EndpointSource source ) { boolean result = this.sources.remove( source ); for( ISourceChangeListener listener : this.listeners ) listener.sourceRemoved( source ); source.dispose(); storeSources(); return result; } /** * @param source */ public void updateSource( EndpointSource source ) { source.refreshServiceUnitList(); for( ISourceChangeListener listener : this.listeners ) listener.sourceChanged( source ); } /** * @param listener * @return * @see java.util.List#add(java.lang.Object) */ public boolean registerListener( ISourceChangeListener listener ) { return this.listeners.add( listener ); } /** * @param listener * @return * @see java.util.List#remove(java.lang.Object) */ public boolean unregisterListener( ISourceChangeListener listener ) { return this.listeners.remove( listener ); } /** * Restores the saved sources. * <p> * If no source was saved, the workspace source is added. * </p> */ private void restoreSavedSources() { // Workspace this.sources.add( this.currentWorkspaceSource ); // External workspaces IPreferenceStore store = PetalsServicesPlugin.getDefault().getPreferenceStore(); String prefs = store.getString( EXT_WK_SRC_PREF ); for( String pref : prefs.split( ";;" )) { if( pref.trim().length() == 0 ) continue; File f = new File( pref ); if( f.exists()) this.sources.add( new ExternalWorkspaceSource( f )); } // SA Folders prefs = store.getString( SA_FLDR_SRC_PREF ); for( String pref : prefs.split( ";;" )) { if( pref.trim().length() == 0 ) continue; File f = new File( pref ); if( f.exists()) this.sources.add( new SaDirectorySource( f, false, false )); } } /** * Saves the sources in the preferences, so that they can be restored at next startup. */ private void storeSources() { StringBuffer extWk = new StringBuffer(); StringBuffer saFldr = new StringBuffer(); for( EndpointSource source : this.sources ) { if( source instanceof ExternalWorkspaceSource ) { extWk.append(((ExternalWorkspaceSource) source).getDirectory().getAbsolutePath()); extWk.append( ";;" ); } else if( source instanceof SaDirectorySource ) { saFldr.append(((SaDirectorySource) source).getDirectoryOrSaFile().getAbsolutePath()); saFldr.append( ";;" ); } } IPreferenceStore store = PetalsServicesPlugin.getDefault().getPreferenceStore(); store.setValue( EXT_WK_SRC_PREF, extWk.toString()); store.setValue( SA_FLDR_SRC_PREF, saFldr.toString()); } /** * Handles workspace changes to notify listeners when workspace end-points were modified. */ @Override public void resourceChanged( IResourceChangeEvent event ) { try { event.getDelta().accept( new IResourceDeltaVisitor() { boolean stopSearching = false; @Override public boolean visit( IResourceDelta delta ) throws CoreException { if( this.stopSearching ) return false; IResource resource = delta.getResource(); // Processing projects if( resource instanceof IProject ) { IProject project = (IProject) resource; // Project was deleted: update the workspace source and do not go further if( delta.getKind() == IResourceDelta.REMOVED ) { updateSource( SourceManager.this.currentWorkspaceSource ); this.stopSearching = true; return false; } // Filter the project return project.isAccessible() && ServiceProjectRelationUtils.isSuProject( project ); } // Processing files else if( resource instanceof IFile ) { if( resource.getName().equals( "jbi.xml" ) || resource.getName().equals( ".jbi-metadata" )) { updateSource( SourceManager.this.currentWorkspaceSource ); this.stopSearching = true; } return false; } return true; } }); } catch( CoreException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } } }