/* ************************************************************************* IT Mill Toolkit Development of Browser User Interfaces Made Easy Copyright (C) 2000-2006 IT Mill Ltd ************************************************************************* This product is distributed under commercial license that can be found from the product package on license.pdf. Use of this product might require purchasing a commercial license from IT Mill Ltd. For guidelines on usage, see licensing-guidelines.html ************************************************************************* For more information, contact: IT Mill Ltd phone: +358 2 4802 7180 Ruukinkatu 2-4 fax: +358 2 4802 7181 20540, Turku email: info@itmill.com Finland company www: www.itmill.com Primary source for information and releases: www.itmill.com ********************************************************************** */ package com.itmill.toolkit.terminal.web; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Stack; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.SAXException; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.Attributes; /** * This class provides an interface to the meta-information regarding a * particular theme. This entails for instanace the inheritance tree of the * various xsl-template files, the different requirments that the theme imposes * on the client browser, etc. *
* The WebAdapter uses themes to convert the UIDL description into client * representation, typically HTML or XHTML. A theme consists of set of XSL * template files which are used to perform XSL transform. *
** XSL files are divided into sets, which can have requirements. A file set is * included in transformation only if the given requirements are met. Following * requirements are supported: *
* The theme description is XML data, and it can be loaded from file or stream.
* The default filename is specified by Theme.DESCRIPTIONFILE
.
*
*
true
if terminal is compatible with this
* rule,otherwise false
.
*
*/
public boolean isMet(WebBrowser terminal);
}
/**
* Generic requirement collection interface. Requirement collection
* introducing methods for combining requirements into single requirement.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public interface RequirementCollection extends Requirement {
/**
* Adds the new requirement to this collection.
*
* @param requirement
* the Requirement to be added.
*/
public void addRequirement(Requirement requirement);
/**
* Removes the requirement from this collection.
*
* @param requirement
* the Requirement to be removed.
*/
public void removeRequirement(Requirement requirement);
}
/**
* Logical NOT requirement. Requirement implementing logical NOT operation.
* Wraps an another requirement and negates the meaning of it.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class NotRequirement implements Requirement {
private Requirement requirement;
/**
* Create a new NOT requirement based on another requirement.
*
* @param requirement
* the requirement to be negated.
*/
public NotRequirement(Requirement requirement) {
this.requirement = requirement;
}
/**
* Check that this requirement is met by given type of browser.
*
* @param terminal
* the type of the web browser.
* @return true
if terminal is compatible with this
* rule,otherwise false
.
*
*/
public boolean isMet(WebBrowser terminal) {
return !this.requirement.isMet(terminal);
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return "not(" + requirement + ")";
}
}
/**
* Logical AND requirement. Implements a collection of requirements
* combining the included requirements using logical AND operation.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class AndRequirement implements RequirementCollection {
private Collection requirements = new LinkedList();
public AndRequirement() {
}
/**
*
* @param requirements
*/
public AndRequirement(Collection requirements) {
this.requirements.addAll(requirements);
}
/**
*
* @param req1
* @param req2
*/
public AndRequirement(Requirement req1, Requirement req2) {
this.addRequirement(req1);
this.addRequirement(req2);
}
/**
* Adds the new requirement to this collection.
*
* @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#addRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
*/
public void addRequirement(Requirement requirement) {
this.requirements.add(requirement);
}
/**
* Removes the requirement from this collection.
*
* @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#removeRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
*/
public void removeRequirement(Requirement requirement) {
this.requirements.remove(requirement);
}
/**
* Checks that all os the requirements in this collection are met.
*
* @param terminal
* the type of the web browser.
* @see Theme.Requirement#isMet(WebBrowser)
*/
public boolean isMet(WebBrowser terminal) {
for (Iterator i = this.requirements.iterator(); i.hasNext();) {
if (!((Requirement) i.next()).isMet(terminal)) {
return false;
}
}
return true;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
String str = "";
for (Iterator i = this.requirements.iterator(); i.hasNext();) {
if (!"".equals(str))
str += " AND ";
str += "(" + ((Requirement) i.next()).toString() + ")";
}
return str;
}
}
/**
* Logical OR requirement. Implements a collection of requirements combining
* the included requirements using logical AND operation.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class OrRequirement implements RequirementCollection {
private Collection requirements = new LinkedList();
public OrRequirement() {
}
/**
*
* @param requirements
*/
public OrRequirement(Collection requirements) {
this.requirements.addAll(requirements);
}
/**
*
* @param req1
* @param req2
*/
public OrRequirement(Requirement req1, Requirement req2) {
this.addRequirement(req1);
this.addRequirement(req2);
}
/**
* Adds the new requirement to this collection.
*
* @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#addRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
*/
public void addRequirement(Requirement requirement) {
this.requirements.add(requirement);
}
/**
* Removes the requirement from this collection.
*
* @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#removeRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
*/
public void removeRequirement(Requirement requirement) {
this.requirements.remove(requirement);
}
/**
* Checks that some of the requirements in this collection is met.
*
* @param terminal
* the type of the web browser.
* @see Theme.Requirement#isMet(WebBrowser)
*/
public boolean isMet(WebBrowser terminal) {
for (Iterator i = this.requirements.iterator(); i.hasNext();) {
if (((Requirement) i.next()).isMet(terminal)) {
return true;
}
}
return false;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
String str = "";
for (Iterator i = this.requirements.iterator(); i.hasNext();) {
if (!"".equals(str))
str += " OR ";
str += "(" + ((Requirement) i.next()).toString() + ")";
}
return str;
}
}
/**
* HTTP user agent requirement This requirements is used to ensure that the
* User-Agent string provided in HTTP request headers contains given
* substring.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class AgentRequirement implements Requirement {
private String agentSubstring;
/**
*
* @param agentSubString
*/
public AgentRequirement(String agentSubString) {
this.agentSubstring = agentSubString;
}
/**
* Checks that this requirement is met by given type of browser.
*
* @see com.itmill.toolkit.terminal.web.Theme.Requirement#isMet(com.itmill.toolkit.terminal.web.WebBrowser)
*/
public boolean isMet(WebBrowser terminal) {
return terminal.getBrowserApplication()
.indexOf(this.agentSubstring) >= 0;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return this.agentSubstring;
}
}
/**
* Javascript version requirement This requirement is used to ensure a
* certain level of JavaScript version support.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class JavaScriptRequirement implements Requirement {
private WebBrowser.JavaScriptVersion requiredVersion;
/**
*
* @param requiredVersion
*/
public JavaScriptRequirement(
WebBrowser.JavaScriptVersion requiredVersion) {
this.requiredVersion = requiredVersion;
}
/**
* Checks that this requirement is met by given type of browser.
*
* @see com.itmill.toolkit.terminal.web.Theme.Requirement#isMet(com.itmill.toolkit.terminal.web.WebBrowser)
*/
public boolean isMet(WebBrowser terminal) {
if (terminal.getJavaScriptVersion().supports(this.requiredVersion))
return true;
return false;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return this.requiredVersion.toString();
}
}
/**
* Markup language version requirement. This requirement is used to ensure a
* certain level of Markup language version support.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class MarkupLanguageRequirement implements Requirement {
private WebBrowser.MarkupVersion requiredVersion;
/**
*
* @param requiredVersion
*/
public MarkupLanguageRequirement(
WebBrowser.MarkupVersion requiredVersion) {
this.requiredVersion = requiredVersion;
}
/**
* Checks that this requirement is met by given type of browser.
*
* @see com.itmill.toolkit.terminal.web.Theme.Requirement#isMet(com.itmill.toolkit.terminal.web.WebBrowser)
*/
public boolean isMet(WebBrowser terminal) {
if (terminal.getMarkupVersion().supports(this.requiredVersion))
return true;
return false;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return this.requiredVersion.toString();
}
}
/**
* Theme XSL file description Description of a single XSL file included a
* theme.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class File {
private String name;
/**
* Creates a new file.
*
* @param name
* the Name of the file.
*/
public File(String name) {
this.name = name;
}
/**
* Gets the name of the file. The file name is relative and unique
* within a theme.
*
* @return the Name of the file.
*/
public String getName() {
return this.name;
}
/**
* Does this file support the given terminal. Single file requirements
* are not supported and therefore this always returns true.
*
* @param terminal
* the type of the web browser.
* @return Always returns true.
* @see Theme.Fileset
*/
public boolean supports(WebBrowser terminal) {
return true;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return this.getName();
}
}
/**
* A recursive set of files sharing the same requirements.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class Fileset extends File {
private RequirementCollection requirements = new AndRequirement();
private Collection files = new LinkedList();
private String mode;
/**
* Creates a new empty fileset.
*
* @param mode
*
*/
public Fileset(String mode) {
super(null);
this.mode = mode;
}
/**
* Adds a file into fileset.
*
* @param file
* the file to add.
*/
private void addFile(File file) {
this.files.add(file);
}
/**
* Gets the requirements in this fileset.
*
* @return the requirements.
*/
private RequirementCollection getRequirements() {
return this.requirements;
}
/**
* Gets the list of all files in this theme.
*
* @return the list of filenames.
*/
public List getFileNames() {
List list = new LinkedList();
for (Iterator i = this.files.iterator(); i.hasNext();) {
File f = (File) i.next();
// Recursively add included filesets
if (f instanceof Fileset) {
list.addAll(((Fileset) f).getFileNames());
} else {
list.add(f.getName());
}
}
return list;
}
/**
* Gets the list of file names matching WebBrowserType.
*
* @param terminal
* the type of the web browser.
* @param mode
* @return the list of filenames supporting the given terminal.
*/
public List getFileNames(WebBrowser terminal, String mode) {
List list = new LinkedList();
// If this set is not supported by the terminal or is explicitly set
// into
// another mode, no files are given
if (!this.supports(terminal)
|| (this.mode != null && !this.mode.equals(mode)))
return list;
for (Iterator i = this.files.iterator(); i.hasNext();) {
File f = (File) i.next();
// Recursively add included filesets if they are
// supported
if (f instanceof Fileset) {
list.addAll(((Fileset) f).getFileNames(terminal, mode));
} else {
list.add(f.getName());
}
}
return list;
}
/**
* Does this file support the given terminal.
*
* @terminal the type of the web browser.
* @return True if fileset supports the given browser. False otherwise.
*/
public boolean supports(WebBrowser terminal) {
if (requirements.isMet(terminal))
return true;
return false;
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
return "name=[" + this.getName() + "] requires=["
+ this.requirements + "] files=[" + files + "]";
}
}
/**
* Gets the author of this theme.
*
* @return the Author of the theme.
*/
public Author getAuthor() {
return author;
}
/**
* Gets the name of this theme.
*
* @return the Name of the theme.
*/
public String getName() {
return name;
}
/**
* Gets the name of the parent theme.
*
* @return the name of the parent theme.
*/
public String getParent() {
return parentTheme;
}
/**
* Gets the theme description.
*
* @return the theme description.
*/
public String getDescription() {
return description;
}
}