blob: 671bb739e0ccb55beed64897b1691366e7a9d421 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Chase Technology Ltd - http://www.chasetechnology.co.uk
* 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:
* Doug Satchwell (Chase Technology Ltd) - initial API and implementation
* David Carver (STAR) - bug 243577 - Added retrieving all called-templates.
*******************************************************************************/
package org.eclipse.wst.xsl.core.model;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.wst.xsl.core.XSLCore;
import org.eclipse.wst.xsl.core.internal.util.Debug;
/**
* The composed stylesheet, consisting of all templates and variables available via imports and includes.
*
* <p>
* The <code>fix()</code> method does the actual work of populating the fields of this, so it must be called before calling any of the other methods.
* </p>
*
* <p>
* Note that this model may not be valid - for instance there may be more than one named template for a given name or more than one global variable with a given name.
* </p>
*
* @author Doug Satchwell
* @since 1.0
*/
public class StylesheetModel extends XSLModelObject
{
private final Stylesheet stylesheet;
boolean circularReference;
final Set<IFile> files = new HashSet<IFile>();
final Set<Stylesheet> stylesheets = new HashSet<Stylesheet>();
final List<Include> includeModel = new ArrayList<Include>();
final List<Import> importModel = new ArrayList<Import>();
final Set<Template> templateSet = new HashSet<Template>();
final List<Template> templates = new ArrayList<Template>();
final List<Variable> globalVariables = new ArrayList<Variable>();
final List<CallTemplate> callTemplates = new ArrayList<CallTemplate>();
/**
* Create a new instance of this.
*
* @param stylesheet
* the stylesheet that this is the model for
*/
public StylesheetModel(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
}
/**
* Get all stylesheets that are included in this stylesheet anywhere in the hierarchy via either import or include.
*
* @return the set of stylesheets in the entire hierarchy
*/
public List<Include> getIncludes()
{
return includeModel;
}
/**
* Get all files that are included in this stylesheet anywhere in the hierarchy via either import or include.
*
* @return the set of files in the entire hierarchy
*/
public Set<IFile> getFileDependencies()
{
return files;
}
/**
* Get the stylesheet that this is the model for.
*
* @return the stylesheet that this is the model for
*/
public Stylesheet getStylesheet()
{
return this.stylesheet;
}
/**
* Get all global variables that are included in this stylesheet anywhere in the hierarchy via either import or include.
*
* @return the set of files in the entire hierarchy
*/
public List<Variable> getGlobalVariables()
{
return globalVariables;
}
/**
* Get all templates that are included in this stylesheet anywhere in the hierarchy via either import or include.
*
* @return the set of templates in the entire hierarchy
*/
public List<Template> getTemplates()
{
return templates;
}
/**
* A utility method that traverses all stylesheet in the hierarchy of stylesheets (not including the current stylesheet), and adds all their templates to the returned list.
* Therefore the returned list has no regard for whether a template is 'visible' (i.e. whether it might be overridden since it
* was included via an import). The order of the templates in the list is arbitrary.
*
* @return an unordered list of all templates from all stylesheets.
*/
public List<Template> findAllNestedTemplates()
{
List<Template> allTemplates = new ArrayList<Template>();
for (Stylesheet stylesheet : stylesheets)
{
allTemplates.addAll(stylesheet.getTemplates());
}
return allTemplates;
}
/**
* Get all named templates that are included in this stylesheet anywhere in the hierarchy via either import or include which have the given name.
*
* @param name
* the template name
* @return the set of named templates with the given name
*/
public List<Template> getTemplatesByName(String name)
{
List<Template> matching = new ArrayList<Template>(templates.size());
for (Template template : templates)
{
if (name.equals(template.getName()))
matching.add(template);
}
return matching;
}
/**
* Get all templates that match the given template (determined from <code>Template.equals()</code>).
*
* @param toMatch
* the template to match
* @return the set of templates that match
*/
public List<Template> findMatching(Template toMatch)
{
List<Template> matching = new ArrayList<Template>(templates.size());
for (Template template : templates)
{
if (template.equals(toMatch))
matching.add(template);
}
return matching;
}
/**
* Get whether this has a circular reference anywhere in its import/included hierarchy.
*
* @return <code>true</code> if this has a circular reference
*/
public boolean hasCircularReference()
{
return circularReference;
}
/**
* Perform the process of traversing the hierarchy to determine all of the properties of this. Note that this method may force other <code>StylesheetModel</code>'s to be built during the process
* of fixing.
*/
public void fix()
{
long start = System.currentTimeMillis();
if (Debug.debugXSLModel)
{
System.out.println("Fixing " + stylesheet.getFile() + "...");
}
templates.addAll(stylesheet.getTemplates());
templateSet.addAll(stylesheet.getTemplates());
globalVariables.addAll(stylesheet.globalVariables);
callTemplates.addAll(stylesheet.getCalledTemplates());
for (Include inc : stylesheet.getIncludes())
{
handleInclude(inc);
}
for (Import inc : stylesheet.getImports())
{
handleInclude(inc);
}
if (Debug.debugXSLModel)
{
long end = System.currentTimeMillis();
System.out.println("FIX " + stylesheet.getFile() + " in " + (end - start) + "ms");
}
}
private void handleInclude(Include include)
{
IFile file = include.getHrefAsFile();
if (file == null || !file.exists())
{
return;
}
else if (stylesheet.getFile().equals(file) || files.contains(file))
{
circularReference = true;
return;
}
files.add(file);
StylesheetModel includedModel = XSLCore.getInstance().getStylesheet(file);
if (includedModel == null)
return;
stylesheets.add(includedModel.getStylesheet());
globalVariables.addAll(includedModel.globalVariables);
callTemplates.addAll(includedModel.getCallTemplates());
if (include.getIncludeType() == Include.INCLUDE)
{
includeModel.add(include);
templates.addAll(includedModel.getTemplates());
templateSet.addAll(includedModel.getTemplates());
}
else
{
importModel.add((Import)include);
for (Template includedTemplate : includedModel.getTemplates())
{
if (!templateSet.contains(includedTemplate))
{
templates.add(includedTemplate);
templateSet.add(includedTemplate);
}
}
}
}
public Type getModelType()
{
return Type.STYLESHEET_MODEL;
}
public List<CallTemplate> getCallTemplates() {
return callTemplates;
}
}