Sfoglia il codice sorgente

- Renamed default theme to base

- Merged XSLT and AJAX -based themes
- Added automatic browser detection and mode selection
- Added automatic ajax-html page generation
- Added automatic XSLT theme header generation (no more window template modifications needed!)

svn changeset:187/svn branch:toolkit
tags/6.7.0.beta1
Joonas Lehtinen 17 anni fa
parent
commit
333a6a59b6

+ 1
- 1
src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java Vedi File

@@ -114,7 +114,7 @@ public class AjaxApplicationManager implements Paintable.RepaintRequestListener,
application.removeListener((Application.WindowDetachListener) this);
}

public void handleXmlHttpRequest(HttpServletRequest request,
public void handleUidlRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException {

boolean repaintAll = request.getParameter(GET_PARAM_REPAINT_ALL) != null;

+ 155
- 63
src/com/itmill/toolkit/terminal/web/ApplicationServlet.java Vedi File

@@ -52,7 +52,9 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.WeakHashMap;

import javax.servlet.ServletContext;
@@ -136,49 +138,49 @@ public class ApplicationServlet extends HttpServlet implements

private static final String PARAMETER_TRANSFORMER_CACHETIME = "TransformerCacheTime";

private static int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24;
private static final int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24;

private static int DEFAULT_BUFFER_SIZE = 32 * 1024;
private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;

private static int DEFAULT_MAX_TRANSFORMERS = 1;
private static final int DEFAULT_MAX_TRANSFORMERS = 1;

private static int MAX_BUFFER_SIZE = 64 * 1024;
private static final int MAX_BUFFER_SIZE = 64 * 1024;

private static String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap";
private static final String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap";

static String SESSION_ATTR_CONTEXT = "itmill-toolkit-context";
private static final String SESSION_ATTR_CONTEXT = "itmill-toolkit-context";

static String SESSION_ATTR_APPS = "itmill-toolkit-apps";
protected static final String SESSION_ATTR_APPS = "itmill-toolkit-apps";

private static String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener";
private static final String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener";

// TODO Should default or base theme be the default?
private static String DEFAULT_THEME = "default";
protected static final String DEFAULT_THEME = "base";

private static String RESOURCE_URI = "/RES/";
private static final String RESOURCE_URI = "/RES/";

private static String AJAX_UIDL_URI = "/UIDL/";
private static final String AJAX_UIDL_URI = "/UIDL/";

private static String THEME_DIRECTORY_PATH = "WEB-INF/lib/themes/";
private static final String THEME_DIRECTORY_PATH = "WEB-INF/lib/themes/";

private static String THEME_LISTING_FILE = THEME_DIRECTORY_PATH
private static final String THEME_LISTING_FILE = THEME_DIRECTORY_PATH
+ "themes.txt";

private static String DEFAULT_THEME_JAR_PREFIX = "itmill-toolkit-themes";
private static final String DEFAULT_THEME_JAR_PREFIX = "itmill-toolkit-themes";

private static String DEFAULT_THEME_JAR = "WEB-INF/lib/"
private static final String DEFAULT_THEME_JAR = "WEB-INF/lib/"
+ DEFAULT_THEME_JAR_PREFIX + "-" + VERSION + ".jar";

private static String DEFAULT_THEME_TEMP_FILE_PREFIX = "ITMILL_TMP_";
private static final String DEFAULT_THEME_TEMP_FILE_PREFIX = "ITMILL_TMP_";

private static String SERVER_COMMAND_PARAM = "SERVER_COMMANDS";
private static final String SERVER_COMMAND_PARAM = "SERVER_COMMANDS";

private static int SERVER_COMMAND_STREAM_MAINTAIN_PERIOD = 15000;
private static final int SERVER_COMMAND_STREAM_MAINTAIN_PERIOD = 15000;

private static int SERVER_COMMAND_HEADER_PADDING = 2000;
private static final int SERVER_COMMAND_HEADER_PADDING = 2000;

// Maximum delay between request for an user to be considered active (in ms)
private static long ACTIVE_USER_REQUEST_INTERVAL = 1000 * 45;
private static final long ACTIVE_USER_REQUEST_INTERVAL = 1000 * 45;

// Private fields
private Class applicationClass;
@@ -499,15 +501,9 @@ public class ApplicationServlet extends HttpServlet implements
HttpVariableMap variableMap = null;
OutputStream out = response.getOutputStream();
HashSet currentlyDirtyWindowsForThisApplication = new HashSet();
WebApplicationContext appContext = null;
Application application = null;
try {

// If the resource path is unassigned, initialize it
if (resourcePath == null)
resourcePath = request.getContextPath()
+ request.getServletPath() + RESOURCE_URI;

// Handle resource requests
if (handleResourceRequest(request, response))
return;
@@ -523,19 +519,15 @@ public class ApplicationServlet extends HttpServlet implements
if (application == null)
application = createApplication(request);

// Is this a download request from application
DownloadStream download = null;
// Set the last application request date
applicationToLastRequestDate.put(application, new Date());

// Invoke context transaction listeners
if (application != null) {
appContext = (WebApplicationContext) application.getContext();
}
if (appContext != null) {
appContext.startTransaction(application, request);
}
((WebApplicationContext) application.getContext())
.startTransaction(application, request);

// Set the last application request date
applicationToLastRequestDate.put(application, new Date());
// Is this a download request from application
DownloadStream download = null;

// The rest of the process is synchronized with the application
// in order to guarantee that no parallel variable handling is
@@ -546,7 +538,7 @@ public class ApplicationServlet extends HttpServlet implements
String resourceId = request.getPathInfo();
if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) {

getApplicationManager(application).handleXmlHttpRequest(
getApplicationManager(application).handleUidlRequest(
request, response);

return;
@@ -594,6 +586,7 @@ public class ApplicationServlet extends HttpServlet implements
window, t));
}
}

// Remove application if it has stopped
if (!application.isRunning()) {
endApplication(request, response, application);
@@ -634,34 +627,128 @@ public class ApplicationServlet extends HttpServlet implements
window.setTerminal(terminalType);
}

// Find theme and initialize TransformerType
UIDLTransformerType transformerType = null;
if (window.getTheme() != null) {
Theme activeTheme;
if ((activeTheme = this.themeSource
.getThemeByName(window.getTheme())) != null) {
transformerType = new UIDLTransformerType(
terminalType, activeTheme);
} else {
Log
.info("Theme named '"
+ window.getTheme()
+ "' not found. Using system default theme.");
// Find theme
Theme theme = themeSource
.getThemeByName(window.getTheme() != null ? window
.getTheme() : DEFAULT_THEME);
if (theme == null)
throw new ServletException("Default theme (named '"
+ DEFAULT_THEME + "') can not be found");

// If UIDL rendering mode is preferred, a page for it is
// rendered
String renderingMode = theme.getPreferredMode(terminalType,
themeSource);
if (Theme.MODE_UIDL.equals(renderingMode)) {
response.setContentType("text/html");
BufferedWriter page = new BufferedWriter(
new OutputStreamWriter(out));

page
.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");

page.write("<html><head>\n<title>"
+ window.getCaption() + "</title>\n");

Theme t = theme;
Vector themes = new Vector();
themes.add(t);
while (t.getParent() != null) {
String parentName = t.getParent();
t = themeSource.getThemeByName(parentName);
themes.add(t);
}
}
for (int k=themes.size()-1; k>=0; k--) {
t = (Theme) themes.get(k);
Collection files = t.getFileNames(terminalType,
Theme.MODE_UIDL);
for (Iterator i = files.iterator(); i.hasNext();) {
String file = (String) i.next();
if (file.endsWith(".css"))
page
.write("<link rel=\"stylesheet\" href=\""
+ getResourceLocation(t
.getName(),
new ThemeResource(
file))
+ "\" type=\"text/css\" />\n");
else if (file.endsWith(".js"))
page
.write("<script src=\""
+ getResourceLocation(t
.getName(),
new ThemeResource(
file))
+ "\" type=\"text/javascript\"></script>\n");
}

}

page.write("</head><body>\n");

// Use default theme if selected theme was not found.
if (transformerType == null) {
Theme defaultTheme = this.themeSource
.getThemeByName(ApplicationServlet.DEFAULT_THEME);
if (defaultTheme == null) {
throw new ServletException(
"Default theme not found in the specified theme source(s).");
page
.write("<div id=\"ajax-wait\"><div>Loading...</div></div>\n");

page.write("<div id=\"ajax-window\"></div>\n");

page.write("<script language=\"JavaScript\">\n");
page
.write("var client = new ITMillToolkitClient("
+ "document.getElementById('ajax-window'),"
+ "\""
+ getApplicationUrl(request)
+ "/UIDL/"
+ "\",\""
+ resourcePath + ((Theme)themes.get(themes.size()-1)).getName() + "/"
+ "client/\",document.getElementById('ajax-wait'));\n");

// TODO Should we also show debug information?
/*
* var debug =
* document.location.href.split("debug=")[1]; if (debug &&
* debug.split("&")[0] == "1") client.debugEnabled =
* true;
*/

for (int k=themes.size()-1; k>=0; k--) {
t = (Theme) themes.get(k);
String themeObjName = t.getName() + "Theme";
themeObjName = themeObjName.substring(0,1).toUpperCase() + themeObjName.substring(1);
page
.write(" (new "+themeObjName+"(\"" + resourcePath + ((Theme)themes.get(k)).getName() + "/\")).registerTo(client);\n");
}
transformerType = new UIDLTransformerType(terminalType,
defaultTheme);
page.write("client.start();\n");

page.write("</script>\n");

page.write("</body></html>\n");
page.close();

return;
}

// If other than XSLT or UIDL mode is requested
if (!Theme.MODE_XSLT.equals(renderingMode)) {
// TODO More informal message should be given is browser
// is not supported
response.setContentType("text/html");
BufferedWriter page = new BufferedWriter(
new OutputStreamWriter(out));
page.write("<html><head></head><body>");
page.write("Unsupported browser.");
page.write("</body></html>");
page.close();

return;
}

// Initialize Transformer
UIDLTransformerType transformerType = new UIDLTransformerType(
terminalType, theme);

transformer = this.transformerFactory
.getTransformer(transformerType);

@@ -769,9 +856,9 @@ public class ApplicationServlet extends HttpServlet implements
transformerFactory.releaseTransformer(transformer);

// Notify transaction end
if (appContext != null && application != null) {
appContext.endTransaction(application, request);
}
if (application != null)
((WebApplicationContext) application.getContext())
.endTransaction(application, request);

// Clean the function library state for this thread
// for security reasons
@@ -988,6 +1075,11 @@ public class ApplicationServlet extends HttpServlet implements
private boolean handleResourceRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException {

// If the resource path is unassigned, initialize it
if (resourcePath == null)
resourcePath = request.getContextPath() + request.getServletPath()
+ RESOURCE_URI;

String resourceId = request.getPathInfo();

// Check if this really is a resource request

+ 49
- 60
src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java Vedi File

@@ -1,30 +1,30 @@
/* *************************************************************************
IT Mill Toolkit
IT Mill Toolkit

Development of Browser User Intarfaces Made Easy
Development of Browser User Intarfaces Made Easy

Copyright (C) 2000-2006 IT Mill Ltd
*************************************************************************
Copyright (C) 2000-2006 IT Mill Ltd
*************************************************************************

This product is distributed under commercial license that can be found
from the product package on license/license.txt. Use of this product might
require purchasing a commercial license from IT Mill Ltd. For guidelines
on usage, see license/licensing-guidelines.html
This product is distributed under commercial license that can be found
from the product package on license/license.txt. Use of this product might
require purchasing a commercial license from IT Mill Ltd. For guidelines
on usage, see license/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
*************************************************************************
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;

@@ -34,12 +34,15 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/** Theme source for consisting of collection of other theme sources.
* This class is used to implement the retrieval of themes
* from multiple sources. Also this class implements the inheritance
* of themes by first retrieving the relevant parent theme information.
/**
* Theme source for consisting of collection of other theme sources. This class
* is used to implement the retrieval of themes from multiple sources. Also this
* class implements the inheritance of themes by first retrieving the relevant
* parent theme information.
*
* @author IT Mill Ltd.
* @version @VERSION@
* @version
* @VERSION@
* @since 3.0
*/
public class CollectionThemeSource implements ThemeSource {
@@ -54,10 +57,11 @@ public class CollectionThemeSource implements ThemeSource {
}

/**
* @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme, WebBrowser)
* @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme,
* WebBrowser)
*/
public Collection getXSLStreams(Theme theme, WebBrowser type)
throws ThemeException {
throws ThemeException {
Collection xslFiles = new LinkedList();

// Add parent theme XSL
@@ -74,17 +78,16 @@ public class CollectionThemeSource implements ThemeSource {
}

private Collection getParentXSLStreams(Theme theme, WebBrowser type)
throws ThemeException {
throws ThemeException {
Collection xslFiles = new LinkedList();
Collection parents = theme.getParentThemes();
for (Iterator i = parents.iterator(); i.hasNext();) {
String name = (String) i.next();
Theme parent = this.getThemeByName(name);
String parentName = theme.getParent();
if (parentName != null) {
Theme parent = this.getThemeByName(parentName);
if (parent != null) {
xslFiles.addAll(this.getXSLStreams(parent, type));
} else {
throw new ThemeSource.ThemeException(
"Parent theme not found for name: " + name);
"Parent theme not found for name: " + parentName);
}
}
return xslFiles;
@@ -112,7 +115,7 @@ public class CollectionThemeSource implements ThemeSource {
int delim = resourceId.indexOf("/");
String subResourceId = "";
String themeName = "";
if (delim >=0 && delim < resourceId.length() - 1) {
if (delim >= 0 && delim < resourceId.length() - 1) {
subResourceId = resourceId.substring(delim + 1);
themeName = resourceId.substring(0, delim);
}
@@ -122,8 +125,9 @@ public class CollectionThemeSource implements ThemeSource {
if (themeName.length() > 0) {
Theme t = this.getThemeByName(themeName);
if (t != null) {
themes.add(t.getName());
addAllParents(themes, t);
themes.add(themeName);
if (t.getParent() != null)
themes.add(t.getParent());
}
}

@@ -134,8 +138,8 @@ public class CollectionThemeSource implements ThemeSource {
// Search all sources
for (Iterator i = this.sources.iterator(); i.hasNext();) {
try {
InputStream in =
((ThemeSource) i.next()).getResource(resource);
InputStream in = ((ThemeSource) i.next())
.getResource(resource);
if (in != null)
return in;
} catch (ThemeException e) {
@@ -144,26 +148,8 @@ public class CollectionThemeSource implements ThemeSource {
}
}

throw new ThemeException(
"Theme resource not found:"
+ subResourceId
+ " in themes "
+ themes);
}
/** Recusrivelu get list of parent themes in inheritace order.
*
* @param t Theme which parents should be listed
* @return Collection of themes in inheritance order.
*/
private void addAllParents(List list, Theme t) {
if (t == null)
return;

List parents = t.getParentThemes();
list.addAll(parents);
for (Iterator i = parents.iterator(); i.hasNext();) {
addAllParents(list, this.getThemeByName((String) i.next()));
}
throw new ThemeException("Theme resource not found:" + subResourceId
+ " in themes " + themes);
}

/**
@@ -190,8 +176,11 @@ public class CollectionThemeSource implements ThemeSource {
return null;
}

/**Add new theme source to this collection.
* @param source Theme source to be added.
/**
* Add new theme source to this collection.
*
* @param source
* Theme source to be added.
*/
public void add(ThemeSource source) {
this.sources.add(source);

+ 34
- 21
src/com/itmill/toolkit/terminal/web/Theme.java Vedi File

@@ -172,8 +172,8 @@ public class Theme extends DefaultHandler {
/** Author of the theme. */
private Author author;

/** List of parent themes */
private List parentThemes = new LinkedList();
/** Name of the theme, which this theme extends */
private String parentTheme = null;

/** Fileset of included XSL files. */
private Fileset files = null;
@@ -234,26 +234,30 @@ public class Theme extends DefaultHandler {
* Get the preferred operating mode supported by this theme for given
* terminal.
*/
public String getPreferredMode(WebBrowser terminal) {
public String getPreferredMode(WebBrowser terminal, ThemeSource themeSource) {

// If no supported modes are declared, then we use parents preferred
// mode
if (parentThemes != null && parentThemes.size() > 0
&& supportedModes.keySet().isEmpty())
return ((Theme) parentThemes.get(0)).getPreferredMode(terminal);

if (parentTheme != null
&& supportedModes.keySet().isEmpty()) {
Theme parent = themeSource.getThemeByName(parentTheme);
if (parent == null)
throw new IllegalStateException("Parent theme '"+parentTheme+"' is not found for theme '"+getName()+"'.");
return parent.getPreferredMode(terminal, themeSource);
}
// Iterate and test the modes in order
for (Iterator i = supportedModes.keySet().iterator(); i.hasNext();) {
String mode = (String) i.next();
if (supportsMode(mode, terminal))
if (supportsMode(mode, terminal,themeSource))
return mode;
}

return MODE_FALLBACK;
return null;
}

/** Tests if this theme suppors given mode */
public boolean supportsMode(String mode, WebBrowser terminal) {
public boolean supportsMode(String mode, WebBrowser terminal, ThemeSource themeSource) {

// Theme must explicitly support the given mode
RequirementCollection rc = (RequirementCollection) supportedModes
@@ -262,9 +266,13 @@ public class Theme extends DefaultHandler {
return false;

// All parents must also support the mode
for (Iterator i = parentThemes.iterator(); i.hasNext();)
if (!((Theme) i.next()).supportsMode(mode, terminal))
return false;
if (parentTheme != null) {
Theme parent = themeSource.getThemeByName(parentTheme);
if (parent == null)
throw new IllegalStateException("Parent theme '"+parentTheme+"' is not found for theme '"+getName()+"'.");
if(!parent.supportsMode(mode, terminal, themeSource))
return false;
}

return true;
}
@@ -324,7 +332,9 @@ public class Theme extends DefaultHandler {
if (this.name.equals(themeName))
throw new IllegalArgumentException("Theme " + this.name
+ " extends itself.");
this.parentThemes.add(themeName);
if (parentTheme != null)
throw new IllegalArgumentException("Only one extends statement is allowed");
this.parentTheme = themeName;
} else if (TAG_FILE.equals(qName)) {
File f = new File(atts.getValue(ATTR_NAME));
if (this.openFilesets.isEmpty()) {
@@ -437,6 +447,11 @@ public class Theme extends DefaultHandler {
this.modesListCurrentlyOpen = false;
} else if (TAG_MODE.equals(qName)) {
this.currentlyOpenMode = null;
} else if (TAG_OR.equals(qName) || TAG_AND.equals(qName)) {
RequirementCollection r = (RequirementCollection) openRequirements.pop();
if (openRequirements.size() < 1)
throw new IllegalStateException();
((RequirementCollection)openRequirements.peek()).addRequirement(r);
}
}

@@ -532,8 +547,8 @@ public class Theme extends DefaultHandler {
* @see java.lang.Object#toString()
*/
public String toString() {
return this.name + " author=[" + this.author + "]" + " inherits="
+ parentThemes + "]" + " files={"
return this.name + " author='" + this.author + "'" + (parentTheme != null ? " inherits='"
+ parentTheme + "'" : "" )+ " files={"
+ (files != null ? files.toString() : "null") + "}";
}

@@ -1082,13 +1097,11 @@ public class Theme extends DefaultHandler {
}

/**
* Returns the list of parent themes of this theme. Returns list of all
* inherited themes in the inheritance order.
* Returns the name of the parent theme.
*
* @return List of parent theme instances.
*/
public List getParentThemes() {
return parentThemes;
public String getParent() {
return parentTheme;
}

/** Get theme description */

+ 1
- 1
src/com/itmill/toolkit/terminal/web/WebBrowser.java Vedi File

@@ -100,7 +100,7 @@ public class WebBrowser implements Terminal {
* @return Name of the terminal window
*/
public String getDefaultTheme() {
return "default";
return ApplicationServlet.DEFAULT_THEME;
}

/** Get the name and version of the web browser application.

Loading…
Annulla
Salva