blob: 64489b52814b755eac03407524a421162db858ec [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
*******************************************************************************/
package org.eclipse.wst.xsl.core.internal.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;
/**
* 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
*/
public class StylesheetModel
{
private final Stylesheet stylesheet;
boolean circularReference;
final Set<IFile> files = new HashSet<IFile>();
final Set<Stylesheet> stylesheets = new HashSet<Stylesheet>();
final Set<Template> templateSet = new HashSet<Template>();
final List<Template> templates = new ArrayList<Template>();
final List<Variable> globalVariables = new ArrayList<Variable>();
/**
* 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 Set<Stylesheet> getIncludedStylesheets()
{
return stylesheets;
}
/**
* 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;
}
/**
* 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()
{
// System.out.println("Fixing "+stylesheet.getFile()+"...");
// long start = System.currentTimeMillis();
templates.addAll(stylesheet.templates);
templateSet.addAll(stylesheet.templates);
for (Include inc : stylesheet.includes)
{
handleInclude(inc);
}
for (Include inc : stylesheet.imports)
{
handleInclude(inc);
}
// 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());
if (include.getIncludeType() == Include.INCLUDE)
{
templates.addAll(includedModel.templates);
templateSet.addAll(includedModel.templates);
}
else
{
for (Template includedTemplate : includedModel.templates)
{
if (!templateSet.contains(includedTemplate))
{
templates.add(includedTemplate);
templateSet.add(includedTemplate);
}
}
}
}
}