/******************************************************************************
* 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 );
}
}
}