/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.studio.templateeditor;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.commons.collections.map.MultiValueMap;
import org.apache.directory.api.ldap.model.schema.ObjectClass;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore;
import org.apache.directory.studio.templateeditor.model.ExtensionPointTemplate;
import org.apache.directory.studio.templateeditor.model.FileTemplate;
import org.apache.directory.studio.templateeditor.model.Template;
import org.apache.directory.studio.templateeditor.model.parser.TemplateIO;
import org.apache.directory.studio.templateeditor.model.parser.TemplateIOException;
/**
* This class is used to manage the templates.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class TemplatesManager
{
/** The preference delimiter used for default and disabled templates */
private static String PREFERENCE_DELIMITER = ";"; //$NON-NLS-1$
/** The preference sub delimiter used for default templates */
private static String PREFERENCE_SUB_DELIMITER = ":"; //$NON-NLS-1$
/** The plugin's preference store */
private IPreferenceStore preferenceStore;
/** The list containing all the templates */
private List<Template> templatesList = new ArrayList<Template>();
/** The maps containing all the templates by their id */
private Map<String, Template> templatesByIdMap = new HashMap<String, Template>();
/** The maps containing all the templates by ObjectClassDescription */
private MultiValueMap templatesByStructuralObjectClassMap = new MultiValueMap();
/** The list containing *only* the IDs of the disabled templates */
private List<String> disabledTemplatesList = new ArrayList<String>();
/** The map containing the default templates */
private Map<ObjectClass, String> defaultTemplatesMap = new HashMap<ObjectClass, String>();
/** The list of listeners */
private List<TemplatesManagerListener> listeners = new ArrayList<TemplatesManagerListener>();
/**
* Creates a new instance of TemplatesManager.
*
* @param preferenceStore
* the plugin's preference store
*/
public TemplatesManager( IPreferenceStore preferenceStore )
{
this.preferenceStore = preferenceStore;
loadDefaultTemplates();
loadDisabledTemplates();
loadTemplates();
setDefaultTemplates();
}
/**
* Adds a listener.
*
* @param listener
* the listener
* @return
* <code>true</code> (as per the general contract of the
* <code>Collection.add</code> method).
*/
public boolean addListener( TemplatesManagerListener listener )
{
return listeners.add( listener );
}
/**
* Removes a listener.
*
* @param listener
* the listener
* @return
* <code>true</code> if this templates manager contained
* the specified listener.
*/
public boolean removeListener( TemplatesManagerListener listener )
{
return listeners.remove( listener );
}
/**
* Fires a "fireTemplateAdded" event to all the listeners.
*
* @param template
* the added template
*/
private void fireTemplateAdded( Template template )
{
for ( TemplatesManagerListener listener : listeners.toArray( new TemplatesManagerListener[0] ) )
{
listener.templateAdded( template );
}
}
/**
* Fires a "templateRemoved" event to all the listeners.
*
* @param template
* the removed template
*/
private void fireTemplateRemoved( Template template )
{
for ( TemplatesManagerListener listener : listeners.toArray( new TemplatesManagerListener[0] ) )
{
listener.templateRemoved( template );
}
}
/**
* Fires a "templateEnabled" event to all the listeners.
*
* @param template
* the enabled template
*/
private void fireTemplateEnabled( Template template )
{
for ( TemplatesManagerListener listener : listeners.toArray( new TemplatesManagerListener[0] ) )
{
listener.templateEnabled( template );
}
}
/**
* Fires a "templateDisabled" event to all the listeners.
*
* @param template
* the disabled template
*/
private void fireTemplateDisabled( Template template )
{
for ( TemplatesManagerListener listener : listeners.toArray( new TemplatesManagerListener[0] ) )
{
listener.templateDisabled( template );
}
}
/**
* Loads the templates
*/
private void loadTemplates()
{
// Loading the templates added using the extension point
loadExtensionPointTemplates();
// Loading the templates added via files on the disk (added by the user)
loadFileTemplates();
}
/**
* Loads the templates added using the extension point.
*/
private void loadExtensionPointTemplates()
{
// Getting the extension point
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
"org.apache.directory.studio.templateeditor.templates" ); //$NON-NLS-1$
// Getting all the extensions
IConfigurationElement[] members = extensionPoint.getConfigurationElements();
if ( members != null )
{
// For each extension: load the template
for ( int m = 0; m < members.length; m++ )
{
IConfigurationElement member = members[m];
// Getting the URL of the file associated with the extension
String contributorName = member.getContributor().getName();
String filePathInPlugin = member.getAttribute( "file" ); //$NON-NLS-1$
URL fileUrl = Platform.getBundle( contributorName ).getResource( filePathInPlugin );
// Checking if the URL is null
if ( filePathInPlugin == null )
{
// Logging the error
EntryTemplatePluginUtils.logError( new NullPointerException(), Messages
.getString( "TemplatesManager.AnErrorOccurredWhenParsingTheTemplate3Params" ), contributorName, //$NON-NLS-1$
filePathInPlugin, Messages.getString( "TemplatesManager.URLCreatedForTheTemplateIsNull" ) ); //$NON-NLS-1$
}
// Parsing the template and adding it to the templates list
try
{
InputStream is = fileUrl.openStream();
ExtensionPointTemplate template = TemplateIO.readAsExtensionPointTemplate( is );
templatesList.add( template );
templatesByIdMap.put( template.getId(), template );
templatesByStructuralObjectClassMap.put( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( template.getStructuralObjectClass() ), template );
is.close();
}
catch ( TemplateIOException e )
{
// Logging the error
EntryTemplatePluginUtils.logError( e, Messages
.getString( "TemplatesManager.AnErrorOccurredWhenParsingTheTemplate3Params" ), //$NON-NLS-1$
contributorName, filePathInPlugin, e.getMessage() );
}
catch ( IOException e )
{
// Logging the error
EntryTemplatePluginUtils.logError( e, Messages
.getString( "TemplatesManager.AnErrorOccurredWhenParsingTheTemplate3Params" ), contributorName, //$NON-NLS-1$
filePathInPlugin, e.getMessage() );
}
}
}
}
/**
* Loads the templates added via files on the disk (added by the user).
*/
private void loadFileTemplates()
{
// Getting the templates folder
File templatesFolder = getTemplatesFolder().toFile();
// If the templates folder does not exist, we exit
if ( !templatesFolder.exists() )
{
return;
}
// Loading the templates contained in the templates folder
String[] templateNames = templatesFolder.list( new FilenameFilter()
{
public boolean accept( File dir, String name )
{
return name.endsWith( ".xml" ); //$NON-NLS-1$
}
} );
// If there are no templates available, we exit
if ( ( templateNames == null ) || ( templateNames.length == 0 ) )
{
return;
}
// Loading each template
for ( String templateName : templateNames )
{
// Creating the template file
File templateFile = new File( templatesFolder, templateName );
// Parsing the template and adding it to the templates list
try
{
InputStream is = new FileInputStream( templateFile );
FileTemplate template = TemplateIO.readAsFileTemplate( is );
templatesList.add( template );
templatesByIdMap.put( template.getId(), template );
templatesByStructuralObjectClassMap.put( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( template.getStructuralObjectClass() ), template );
is.close();
}
catch ( TemplateIOException e )
{
// Logging the error
EntryTemplatePluginUtils.logError( e, Messages
.getString( "TemplatesManager.AnErrorOccurredWhenParsingTheTemplate2Params" ), //$NON-NLS-1$
templateFile.getAbsolutePath(), e.getMessage() );
}
catch ( IOException e )
{
// Logging the error
EntryTemplatePluginUtils.logError( e, Messages
.getString( "TemplatesManager.AnErrorOccurredWhenParsingTheTemplate2Params" ), //$NON-NLS-1$
templateFile.getAbsolutePath(), e.getMessage() );
}
}
}
/**
* Adds a template from a file on the disk.
*
* @param templateFile
* the template file
* @return
* <code>true</code> if the template file has been successfully added,
* <code>false</code> if the template file has not been added
*/
public boolean addTemplate( File templateFile )
{
// Getting the file template
FileTemplate fileTemplate = getFileTemplate( templateFile );
if ( fileTemplate == null )
{
// If the file is not valid, we simply return
return false;
}
// Verifying if a template with a similar ID does not already exist
if ( templatesByIdMap.containsKey( fileTemplate.getId() ) )
{
// Logging the error
EntryTemplatePluginUtils.logError( null, Messages
.getString( "TemplatesManager.TheTemplateFileCouldNotBeAddedBecauseATemplateWithSameIDAlreadyExist" ), //$NON-NLS-1$
templateFile.getAbsolutePath() );
return false;
}
// Verifying the folder containing the templates already exists
// If not we create it
File templatesFolder = getTemplatesFolder().toFile();
if ( !templatesFolder.exists() )
{
// The folder does not exist, we need to create it.
templatesFolder.mkdirs();
}
// Copying the template in the plugin's folder
try
{
// Creating the file object where the template will be saved
File destinationFile = getTemplatesFolder().append( fileTemplate.getId() + ".xml" ).toFile(); //$NON-NLS-1$
// Checking if the file does not already exist
if ( destinationFile.exists() )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages
.getString( "TemplatesManager.TheTemplateFileCouldNotBeAddedBecauseATemplateWithSameIDAlreadyExist" ), //$NON-NLS-1$
templateFile.getAbsolutePath() );
return false;
}
// Copying the file
EntryTemplatePluginUtils.copyFile( templateFile, destinationFile );
}
catch ( IOException e )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages.getString( "TemplatesManager.TheTemplateFileCouldNotBeCopiedToThePluginsFolder" ), templateFile.getAbsolutePath() ); //$NON-NLS-1$
return false;
}
// Adding the template
templatesList.add( fileTemplate );
templatesByIdMap.put( fileTemplate.getId(), fileTemplate );
templatesByStructuralObjectClassMap.put( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( fileTemplate.getStructuralObjectClass() ), fileTemplate );
// Firing the event
fireTemplateAdded( fileTemplate );
return true;
}
/**
* Get the file template associate with the template file.
*
* @param templateFile
* the template file
* @return
* the associated file template
*/
private FileTemplate getFileTemplate( File templateFile )
{
// Checking if the file exists
if ( !templateFile.exists() )
{
// Logging the error
EntryTemplatePluginUtils.logError( null, Messages
.getString( "TemplatesManager.TheTemplateFileCouldNotBeAddedBecauseItDoesNotExist" ), templateFile //$NON-NLS-1$
.getAbsolutePath() );
return null;
}
// Checking if the file is readable
if ( !templateFile.canRead() )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages.getString( "TemplatesManager.TheTemplateFileCouldNotBeAddedBecauseItCantBeRead" ), templateFile.getAbsolutePath() ); //$NON-NLS-1$
return null;
}
// Trying to parse the template file
FileTemplate fileTemplate = null;
try
{
FileInputStream fis = new FileInputStream( templateFile );
fileTemplate = TemplateIO.readAsFileTemplate( fis );
}
catch ( FileNotFoundException e )
{
// Logging the error
EntryTemplatePluginUtils.logError( e, Messages
.getString( "TemplatesManager.TheTemplateFileCouldNotBeAddedBecauseOfTheFollowingError" ), templateFile //$NON-NLS-1$
.getAbsolutePath(), e.getMessage() );
return null;
}
catch ( TemplateIOException e )
{
// Logging the error
EntryTemplatePluginUtils.logError( e, Messages
.getString( "TemplatesManager.TheTemplateFileCouldNotBeAddedBecauseOfTheFollowingError" ), templateFile //$NON-NLS-1$
.getAbsolutePath(), e.getMessage() );
return null;
}
// Everything went fine, the file is valid
return fileTemplate;
}
/**
* Removes a template.
*
* @param fileTemplate
* the file template to remove
* @return
* <code>true</code> if the file template has been successfully removed,
* <code>false</code> if the template file has not been removed
*/
public boolean removeTemplate( FileTemplate fileTemplate )
{
// Checking if the file template is null
if ( fileTemplate == null )
{
return false;
}
// Checking if the file template exists in the templates set
if ( !templatesList.contains( fileTemplate ) )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages.getString( "TemplatesManager.TheTemplateCouldNotBeRemovedBecauseOfTheFollowingError" ) //$NON-NLS-1$
+ Messages.getString( "TemplatesManager.TheTemplateDoesNotExistInTheTemplateManager" ), fileTemplate.getTitle(), fileTemplate //$NON-NLS-1$
.getId() );
return false;
}
// Creating the file object associated with the template
File templateFile = getTemplatesFolder().append( fileTemplate.getId() + ".xml" ).toFile(); //$NON-NLS-1$
// Checking if the file exists
if ( !templateFile.exists() )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages.getString( "TemplatesManager.TheTemplateCouldNotBeRemovedBecauseOfTheFollowingError" ) //$NON-NLS-1$
+ Messages.getString( "TemplatesManager.TheFileAssociatedWithTheTemplateCouldNotBeFoundAt" ), fileTemplate.getTitle(), //$NON-NLS-1$
fileTemplate.getId(), templateFile.getAbsolutePath() );
return false;
}
// Checking if the file can be written, and thus deleted
if ( !templateFile.canWrite() )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages.getString( "TemplatesManager.TheTemplateCouldNotBeRemovedBecauseOfTheFollowingError" ) //$NON-NLS-1$
+ Messages.getString( "TemplatesManager.TheFileAssociatedWithTheTemplateCanNotBeModified" ), fileTemplate.getTitle(), //$NON-NLS-1$
fileTemplate.getId(), templateFile.getAbsolutePath() );
return false;
}
// Deleting the file
if ( !templateFile.delete() )
{
// Logging the error
EntryTemplatePluginUtils
.logError(
null,
Messages.getString( "TemplatesManager.TheTemplateCouldNotBeRemovedBecauseOfTheFollowingError" ) //$NON-NLS-1$
+ Messages
.getString( "TemplatesManager.AnErrorOccurredWhenRemovingTheFileAssociatedWithTheTemplate" ), fileTemplate //$NON-NLS-1$
.getTitle(), fileTemplate.getId(), templateFile.getAbsolutePath() );
return false;
}
// Removing the template from the disabled templates files
disabledTemplatesList.remove( fileTemplate );
// Removing the template for the templates list
templatesList.remove( fileTemplate );
templatesByIdMap.remove( fileTemplate.getId() );
templatesByStructuralObjectClassMap.remove( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( fileTemplate.getStructuralObjectClass() ) );
// Firing the event
fireTemplateRemoved( fileTemplate );
return true;
}
/**
* Gets the templates.
*
* @return
* the templates
*/
public Template[] getTemplates()
{
return templatesList.toArray( new Template[0] );
}
/**
* Gets the templates folder.
*
* @return
* the templates folder
*/
private static IPath getTemplatesFolder()
{
return EntryTemplatePlugin.getDefault().getStateLocation().append( "templates" ); //$NON-NLS-1$
}
/**
* Loads the {@link List} of disabled templates from the preference store.
*/
private void loadDisabledTemplates()
{
StringTokenizer tokenizer = new StringTokenizer( preferenceStore
.getString( EntryTemplatePluginConstants.PREF_DISABLED_TEMPLATES ), PREFERENCE_DELIMITER );
while ( tokenizer.hasMoreTokens() )
{
disabledTemplatesList.add( tokenizer.nextToken() );
}
}
/**
* Saves the {@link List} of disabled templates to the preference store.
*/
private void saveDisabledTemplates()
{
StringBuffer sb = new StringBuffer();
for ( String disabledTemplateId : disabledTemplatesList )
{
sb.append( disabledTemplateId );
sb.append( PREFERENCE_DELIMITER );
}
preferenceStore.setValue( EntryTemplatePluginConstants.PREF_DISABLED_TEMPLATES, sb.toString() );
}
/**
* Enables the given template.
*
* @param template
* the template
*/
public void enableTemplate( Template template )
{
if ( disabledTemplatesList.contains( template.getId() ) )
{
// Removing the id of the template to the list of disabled templates
disabledTemplatesList.remove( template.getId() );
// Saving the disabled templates list
saveDisabledTemplates();
// Firing the event
fireTemplateEnabled( template );
}
}
/**
* Disables the given template.
*
* @param template
* the template
*/
public void disableTemplate( Template template )
{
if ( !disabledTemplatesList.contains( template.getId() ) )
{
// Adding the id of the template to the list of disabled templates
disabledTemplatesList.add( template.getId() );
// Saving the disabled templates list
saveDisabledTemplates();
// Firing the event
fireTemplateDisabled( template );
}
}
/**
* Indicates if the given template is enabled or not.
*
* @param template
* the template
* @return
* <code>true</code> if the template is enabled,
* <code>false</code> if the template is disabled
*/
public boolean isEnabled( Template template )
{
return !disabledTemplatesList.contains( template.getId() );
}
/**
* Loads the {@link Map} of default templates from the preference store.
*/
private void loadDefaultTemplates()
{
// Getting each default set
StringTokenizer tokenizer = new StringTokenizer( preferenceStore
.getString( EntryTemplatePluginConstants.PREF_DEFAULT_TEMPLATES ), PREFERENCE_DELIMITER );
while ( tokenizer.hasMoreTokens() )
{
String token = tokenizer.nextToken();
// Splitting the default set
String[] splittedToken = token.split( ":" ); //$NON-NLS-1$
if ( splittedToken.length == 2 )
{
// Adding the default template value
defaultTemplatesMap.put( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( splittedToken[0] ), splittedToken[1] );
}
}
}
/**
* Saves the {@link Map} of default templates to the preference store.
*/
private void saveDefaultTemplates()
{
StringBuffer sb = new StringBuffer();
for ( ObjectClass objectClassDescription : defaultTemplatesMap.keySet() )
{
sb.append( objectClassDescription.getNames().get( 0 ) );
sb.append( PREFERENCE_SUB_DELIMITER );
sb.append( defaultTemplatesMap.get( objectClassDescription ) );
sb.append( PREFERENCE_DELIMITER );
}
preferenceStore.setValue( EntryTemplatePluginConstants.PREF_DEFAULT_TEMPLATES, sb.toString() );
}
/**
* Sets the default templates.
*/
private void setDefaultTemplates()
{
for ( Template template : templatesList )
{
if ( isEnabled( template ) )
{
String structuralObjectClass = template.getStructuralObjectClass();
// Checking if a default template is defined
if ( defaultTemplatesMap.get( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( structuralObjectClass ) ) == null )
{
// Assigning this template as the default one
defaultTemplatesMap.put( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( structuralObjectClass ), template.getId() );
}
}
}
// Saving default templates
saveDefaultTemplates();
}
/**
* Sets the given template as default for its structural object class.
*
* @param template
* the template
*/
public void setDefaultTemplate( Template template )
{
if ( isEnabled( template ) )
{
// Removing the old value
defaultTemplatesMap.remove( EntryTemplatePluginUtils.getObjectClassDescriptionFromDefaultSchema( template
.getStructuralObjectClass() ) );
// Setting the new value
defaultTemplatesMap.put( EntryTemplatePluginUtils.getObjectClassDescriptionFromDefaultSchema( template
.getStructuralObjectClass() ), template.getId() );
// Saving default templates
saveDefaultTemplates();
}
}
/**
* Unsets the given template as default for its structural object class.
*
* @param template
* the template
*/
public void unSetDefaultTemplate( Template template )
{
if ( isDefaultTemplate( template ) )
{
defaultTemplatesMap.remove( EntryTemplatePluginUtils.getObjectClassDescriptionFromDefaultSchema( template
.getStructuralObjectClass() ) );
// Saving default template
saveDefaultTemplates();
}
}
/**
* Indicates if the given template is the default one
* for its structural object class or not.
*
* @param template
* the template
* @return
* <code>true</code> if the given template is the default one
* for its structural object class,
* <code>false</code> if not
*/
public boolean isDefaultTemplate( Template template )
{
String defaultTemplateID = defaultTemplatesMap.get( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( template.getStructuralObjectClass() ) );
if ( defaultTemplateID != null )
{
return defaultTemplateID.equalsIgnoreCase( template.getId() );
}
return false;
}
/**
* Indicates whether the given name or OID for an object class has a default template.
*
* @param nameOrOid
* the name or OID
* @return
* <code>true</code> if the given name or OID for an object class has a default template
*/
public boolean hasDefaultTemplate( String nameOrOid )
{
return getDefaultTemplate( nameOrOid ) != null;
}
/**
* Gets the default template associated with given name or OID for an object class.
*
* @param nameOrOid
* @return
* the default template associated with given name or OID for an object class,
* or <code>null</code> if there's no default template
*/
public Template getDefaultTemplate( String nameOrOid )
{
return getTemplateById( defaultTemplatesMap.get( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( nameOrOid ) ) );
}
/**
* Gets the template identified by the given ID.
*
* @param id
* the ID
* @return
* the template identified by the given ID
*/
private Template getTemplateById( String id )
{
return templatesByIdMap.get( id );
}
/**
* Gets the list of templates associated with the given name or OID for an object class.
*
* @param nameOrOid
* the name or OID
* @return
* the list of templates associated with the given name or OID for an object class
* or <code>null</code> if there's no associated template
*/
@SuppressWarnings("unchecked")
public List<Template> getTemplatesByObjectClass( String nameOrOid )
{
return ( List<Template> ) templatesByStructuralObjectClassMap.get( EntryTemplatePluginUtils
.getObjectClassDescriptionFromDefaultSchema( nameOrOid ) );
}
}