Index: core/src/com/icesoft/faces/context/Resource.java =================================================================== --- core/src/com/icesoft/faces/context/Resource.java (revision 16995) +++ core/src/com/icesoft/faces/context/Resource.java Tue Jul 01 21:14:19 EEST 2008 @@ -10,6 +10,13 @@ public interface Resource { /** + * Calculate a digest that uniquely identifies the content of the resource. + * + * @return the digest + */ + String calculateDigest(); + + /** * Open reading stream. * * @return the stream @@ -20,13 +27,31 @@ * Return timestamp when resource was last updated or created. * * @return the timestamp + * @deprecated use {@link Resource.Options#setLastModified} instead */ Date lastModified(); /** - * Calculate a digest that uniquely identifies the content of the resource. + * Set additional options for resource downloading. * - * @return the digest + * @param options + * @throws IOException */ - String calculateDigest(); + void withOptions(Options options) throws IOException; + + /** + * Callback for setting optional download information. + */ + interface Options { + + void setMimeType(String mimeType); + + void setLastModified(Date date); + + void setFileName(String fileName); + + void setExpiresBy(Date date); + + void setAsAttachement(); -} + } +} Index: core/src/com/icesoft/faces/context/StringResource.java =================================================================== --- core/src/com/icesoft/faces/context/StringResource.java (revision 16995) +++ core/src/com/icesoft/faces/context/StringResource.java Tue Jul 01 21:14:19 EEST 2008 @@ -6,7 +6,7 @@ import java.util.Date; public class StringResource implements Resource { - private static final Date LastModified = new Date(); + private final Date lastModified = new Date(); private String content; private String encoding; @@ -24,10 +24,14 @@ } public Date lastModified() { - return LastModified; + return lastModified; } public InputStream open() throws IOException { return new ByteArrayInputStream(content.getBytes(encoding)); } + + public void withOptions(Options options) throws IOException { + options.setMimeType("text/plain; encoding=" + encoding); -} + } +} Index: core/src/com/icesoft/faces/context/BridgeFacesContext.java =================================================================== --- core/src/com/icesoft/faces/context/BridgeFacesContext.java (revision 16995) +++ core/src/com/icesoft/faces/context/BridgeFacesContext.java Tue Jul 01 21:14:19 EEST 2008 @@ -62,7 +62,15 @@ import java.io.IOException; import java.lang.reflect.Method; import java.net.URI; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; import java.util.regex.Pattern; //for now extend BridgeFacesContext since there are so many 'instanceof' tests @@ -374,7 +382,7 @@ responseComplete = false; //Spring Web Flow 2 releases the FacesContext in between lifecycle //phases - if (com.icesoft.util.SeamUtilities.isSpring2Environment()) { + if (com.icesoft.util.SeamUtilities.isSpring2Environment()) { this.viewRoot = null; } // #2807 release thread locals @@ -440,7 +448,7 @@ } public URI loadJavascriptCode(final Resource resource) { - String uri = resourceDispatcher.registerResource("text/javascript", resource).toString(); + String uri = resourceDispatcher.registerResource(resource).toString(); if (!jsCodeURIs.contains(uri)) { jsCodeURIs.add(uri); } @@ -448,7 +456,7 @@ } public URI loadJavascriptCode(Resource resource, ResourceLinker.Handler linkerHandler) { - String uri = resourceDispatcher.registerResource("text/javascript", resource, linkerHandler).toString(); + String uri = resourceDispatcher.registerResource(resource, linkerHandler).toString(); if (!jsCodeURIs.contains(uri)) { jsCodeURIs.add(uri); } @@ -456,7 +464,7 @@ } public URI loadCSSRules(Resource resource) { - String uri = resourceDispatcher.registerResource("text/css", resource).toString(); + String uri = resourceDispatcher.registerResource(resource).toString(); if (!cssRuleURIs.contains(uri)) { cssRuleURIs.add(uri); } @@ -465,29 +473,21 @@ public URI loadCSSRules(Resource resource, ResourceLinker.Handler linkerHandler) { - String uri = resourceDispatcher.registerResource("text/css", resource, linkerHandler).toString(); + String uri = resourceDispatcher.registerResource(resource, linkerHandler).toString(); if (!cssRuleURIs.contains(uri)) { cssRuleURIs.add(uri); } return resolve(uri); } - public URI registerResource(String mimeType, Resource resource) { - return resolve(resourceDispatcher.registerResource(mimeType, resource).toString()); + public URI registerResource(Resource resource) { + return resolve(resourceDispatcher.registerResource(resource).toString()); } - public URI registerResource(String mimeType, Resource resource, ResourceLinker.Handler linkerHandler) { - return resolve(resourceDispatcher.registerResource(mimeType, resource, linkerHandler).toString()); + public URI registerResource(Resource resource, ResourceLinker.Handler linkerHandler) { + return resolve(resourceDispatcher.registerResource(resource, linkerHandler).toString()); } - public URI registerNamedResource(String name, Resource resource) { - return resolve(resourceDispatcher.registerNamedResource(name, resource).toString()); - } - - public URI registerNamedResource(String name, Resource resource, ResourceLinker.Handler linkerHandler) { - return resolve(resourceDispatcher.registerNamedResource(name, resource, linkerHandler).toString()); - } - private URI resolve(String uri) { return URI.create(application.getViewHandler().getResourceURL(this, uri)); } Index: core/src/com/icesoft/faces/context/JarResource.java =================================================================== --- core/src/com/icesoft/faces/context/JarResource.java (revision 16995) +++ core/src/com/icesoft/faces/context/JarResource.java Tue Jul 01 19:59:19 EEST 2008 @@ -5,7 +5,7 @@ import java.util.Date; public class JarResource implements Resource { - private static Date StartTime = new Date(System.currentTimeMillis()); + private final Date lastModified = new Date(); private String path; public JarResource(String path) { @@ -17,10 +17,14 @@ } public Date lastModified() { - return StartTime; + return lastModified; } public InputStream open() throws IOException { return this.getClass().getClassLoader().getResourceAsStream(path); } + + public void withOptions(Options options) throws IOException { + options.setFileName(path); -} + } +} Index: core/src/com/icesoft/faces/context/ByteArrayResource.java =================================================================== --- core/src/com/icesoft/faces/context/ByteArrayResource.java (revision 16995) +++ core/src/com/icesoft/faces/context/ByteArrayResource.java Tue Jul 01 19:59:37 EEST 2008 @@ -6,7 +6,7 @@ import java.util.Date; public class ByteArrayResource implements Resource { - private static final Date LastModified = new Date(); + private final Date lastModified = new Date(); private byte[] content; public ByteArrayResource(byte[] content) { @@ -18,10 +18,14 @@ } public Date lastModified() { - return LastModified; + return lastModified; } public InputStream open() throws IOException { return new ByteArrayInputStream(content); } + + public void withOptions(Options options) throws IOException { + //no options -} + } +} Index: component/src/com/icesoft/faces/component/outputchart/AbstractChart.java =================================================================== --- component/src/com/icesoft/faces/component/outputchart/AbstractChart.java (revision 16995) +++ component/src/com/icesoft/faces/component/outputchart/AbstractChart.java Tue Jul 01 21:14:19 EEST 2008 @@ -33,20 +33,7 @@ package com.icesoft.faces.component.outputchart; -import java.awt.Color; -import java.awt.Paint; -import java.awt.Shape; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.faces.component.UIComponent; -import javax.faces.context.FacesContext; - +import com.icesoft.faces.context.ResourceRegistry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.krysalis.jcharts.Chart; @@ -57,7 +44,14 @@ import org.krysalis.jcharts.properties.PointChartProperties; import org.krysalis.jcharts.test.TestDataGenerator; -import com.icesoft.faces.context.ResourceRegistry; +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import java.awt.*; +import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; public abstract class AbstractChart { private final Log log = LogFactory.getLog(AbstractChart.class); @@ -89,12 +83,12 @@ ByteArrayOutputStream bos = new ByteArrayOutputStream(); JPEGEncoder.encode(getChart(), 1.0f, bos); outputChart.setChartResource(new ChartResource(bos)); - outputChart.setChartURI(((ResourceRegistry) context).registerResource("image/jpeg", outputChart.getChartResource())); + outputChart.setChartURI(((ResourceRegistry) context).registerResource(outputChart.getChartResource())); bos.flush(); bos.close(); } else { - log.equals("The jchart is not defined for the "+ + log.equals("The jchart is not defined for the " + - outputChart.getClientId(FacesContext.getCurrentInstance())+ + outputChart.getClientId(FacesContext.getCurrentInstance()) + ", please check if the proper [type] has been defined"); } } @@ -118,7 +112,7 @@ String type = ((OutputChart) uiComponent).getType(); if (OutputChart.PIE2D_CHART_TYPE.equalsIgnoreCase(type) || OutputChart.PIE3D_CHART_TYPE.equalsIgnoreCase(type)) { - return new PieChart(uiComponent); + return new PieChart(uiComponent); } else { return new AxisChart(uiComponent); } @@ -137,12 +131,12 @@ public String[] getAsStringArray(Object obj) { if (obj instanceof String[]) { - return (String[]) obj; + return (String[]) obj; } else if (obj instanceof String) { return ((String) obj).split(","); } else if (obj instanceof List) { return (String[]) ((List) obj).toArray(new String[0]); - }else { + } else { return null; } } @@ -212,7 +206,7 @@ paintArray[i] = (Paint) objList.get(i); } } else if (obj instanceof String[]) { - String[] colors = (String[]) obj; + String[] colors = (String[]) obj; paintArray = new Paint[colors.length]; for (int i = 0; i < colors.length; i++) { paintArray[i] = colorMap.getColor(colors[i]); @@ -294,14 +288,14 @@ return null; } LegendProperties legendProperties = new LegendProperties(); - legendProperties.setPlacement(legendPlacementMap.getLegendPlacement(legendPlacement)); - Object legendColumns = outputChart.getLegendColumns(); - if (legendColumns instanceof Integer) { + legendProperties.setPlacement(legendPlacementMap.getLegendPlacement(legendPlacement)); + Object legendColumns = outputChart.getLegendColumns(); + if (legendColumns instanceof Integer) { - legendProperties.setNumColumns(((Integer)outputChart.getLegendColumns()).intValue()); + legendProperties.setNumColumns(((Integer) outputChart.getLegendColumns()).intValue()); - }else if (legendColumns instanceof String) { + } else if (legendColumns instanceof String) { - legendProperties.setNumColumns(Integer.parseInt(outputChart.getLegendColumns().toString())); - } - return legendProperties; + legendProperties.setNumColumns(Integer.parseInt(outputChart.getLegendColumns().toString())); + } + return legendProperties; } } @@ -346,17 +340,17 @@ } class LegendPlacementMap extends HashMap { - public LegendPlacementMap() { - this.put("top", new Integer(LegendProperties.TOP)); - this.put("bottom", new Integer(LegendProperties.BOTTOM)); - this.put("left", new Integer(LegendProperties.LEFT)); - this.put("right", new Integer(LegendProperties.RIGHT)); - } - - public int getLegendPlacement(String key) { - if (!super.containsKey(key)) { - return 0; - } - return Integer.parseInt(super.get(key).toString()); - } + public LegendPlacementMap() { + this.put("top", new Integer(LegendProperties.TOP)); + this.put("bottom", new Integer(LegendProperties.BOTTOM)); + this.put("left", new Integer(LegendProperties.LEFT)); + this.put("right", new Integer(LegendProperties.RIGHT)); + } + + public int getLegendPlacement(String key) { + if (!super.containsKey(key)) { + return 0; + } + return Integer.parseInt(super.get(key).toString()); + } } Index: core/src/com/icesoft/faces/context/ResourceRegistry.java =================================================================== --- core/src/com/icesoft/faces/context/ResourceRegistry.java (revision 16995) +++ core/src/com/icesoft/faces/context/ResourceRegistry.java Mon Jun 30 13:58:00 EEST 2008 @@ -63,11 +63,10 @@ * that proper resolution is achieved when template subdirectories or * forwards are used. * - * @param mimeType the mime-type of the resource * @param resource the resource * @return the URI of the resource */ - URI registerResource(String mimeType, Resource resource); + URI registerResource(Resource resource); /** * Register resource to be served. The URI is encoded using @@ -75,37 +74,10 @@ * that proper resolution is achieved when template subdirectories or * forwards are used. * - * @param mimeType the mime-type of the resource * @param resource the resource * @param linkerHandler handler used to specify any other resource relatively * referenced by the main resource (such as '@import' rules) * @return the URI of the resource */ - URI registerResource(String mimeType, Resource resource, ResourceLinker.Handler linkerHandler); - - /** - * Register resource to be served. The URI is encoded using - * {@link javax.faces.application.ViewHandler#getResourceURL(javax.faces.context.FacesContext,String)} so - * that proper resolution is achieved when template subdirectories or - * forwards are used. - * - * @param name the name of the resource - * @param resource the resource - * @return the URI of the resource - */ - URI registerNamedResource(String name, Resource resource); - - /** - * Register resource to be served. The URI is encoded using - * {@link javax.faces.application.ViewHandler#getResourceURL(javax.faces.context.FacesContext,String)} so - * that proper resolution is achieved when template subdirectories or - * forwards are used. - * - * @param name the name of the resource - * @param resource the resource - * @param linkerHandler handler used to specify any other resource relatively - * referenced by the main resource (such as '@import' rules) - * @return the URI of the resource - */ - URI registerNamedResource(String name, Resource resource, ResourceLinker.Handler linkerHandler); + URI registerResource(Resource resource, ResourceLinker.Handler linkerHandler); } Index: core/src/com/icesoft/faces/webapp/http/core/ResourceDispatcher.java =================================================================== --- core/src/com/icesoft/faces/webapp/http/core/ResourceDispatcher.java (revision 16995) +++ core/src/com/icesoft/faces/webapp/http/core/ResourceDispatcher.java Tue Jul 01 21:14:19 EEST 2008 @@ -2,7 +2,11 @@ import com.icesoft.faces.context.Resource; import com.icesoft.faces.context.ResourceLinker; -import com.icesoft.faces.webapp.http.common.*; +import com.icesoft.faces.webapp.http.common.MimeTypeMatcher; +import com.icesoft.faces.webapp.http.common.Request; +import com.icesoft.faces.webapp.http.common.Response; +import com.icesoft.faces.webapp.http.common.ResponseHandler; +import com.icesoft.faces.webapp.http.common.Server; import com.icesoft.faces.webapp.http.common.standard.CompressingServer; import com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer; import com.icesoft.faces.webapp.http.servlet.SessionDispatcher; @@ -35,15 +39,15 @@ compressResource.service(request); } - public URI registerResource(String mimeType, Resource resource) { - return registerResource(mimeType, resource, NOOPHandler); + public URI registerResource(Resource resource) { + return registerResource(resource, NOOPHandler); } - public URI registerResource(final String mimeType, Resource resource, ResourceLinker.Handler handler) { + public URI registerResource(Resource resource, ResourceLinker.Handler handler) { final String name = prefix + encode(resource) + "/"; if (!registered.contains(name)) { registered.add(name); - dispatcher.dispatchOn(".*" + name.replaceAll("\\/", "\\/") + "$", new ResourceServer(mimeType, resource)); + dispatcher.dispatchOn(".*" + name.replaceAll("\\/", "\\/") + "$", new ResourceServer(resource)); if (handler != NOOPHandler) { handler.linkWith(new RelativeResourceLinker(name)); } @@ -52,52 +56,57 @@ return URI.create(name); } - public URI registerNamedResource(String name, Resource resource) { - return registerNamedResource(name, resource, NOOPHandler); - } - - public URI registerNamedResource(String fileName, Resource resource, ResourceLinker.Handler handler) { - final String name = prefix + encode(resource) + "-" + fileName; - if (!registered.contains(name)) { - registered.add(name); - String pathExpression = name.replaceAll("\\/", "\\/").replaceAll("\\.", "\\."); - String type = mimeTypeMatcher.mimeTypeFor(fileName); - dispatcher.dispatchOn(".*" + pathExpression + "$", new ResourceServer(type, resource)); - if (handler != NOOPHandler) { - handler.linkWith(new RelativeResourceLinker(name)); - } - } - - return URI.create(name); - } - public void shutdown() { compressResource.shutdown(); registered.clear(); } - private class ResourceServer implements Server, ResponseHandler { - private ResponseHandler notModified = new ResponseHandler() { + private class ResourceServer implements Server, ResponseHandler, Resource.Options { + private final ResponseHandler notModified = new ResponseHandler() { public void respond(Response response) throws Exception { response.setStatus(304); response.setHeader("ETag", encode(resource)); response.setHeader("Date", new Date()); - response.setHeader("Last-Modified", resource.lastModified()); - response.setHeader("Expires", monitor.expiresBy()); + response.setHeader("Last-Modified", lastModified); + response.setHeader("Expires", expiresBy); } }; - private String mimeType; private final Resource resource; + //default values + private Date lastModified = new Date(); + private Date expiresBy = monitor.expiresBy(); + private String mimeType; + private boolean attachement = false; + private String fileName = ""; - public ResourceServer(String mimeType, Resource resource) { - this.mimeType = mimeType; + public ResourceServer(Resource resource) { this.resource = resource; } + public void setMimeType(String type) { + mimeType = type; + } + + public void setLastModified(Date date) { + lastModified = date; + } + + public void setFileName(String name) { + fileName = name; + } + + public void setExpiresBy(Date date) { + expiresBy = date; + } + + public void setAsAttachement() { + attachement = true; + } + public void service(Request request) throws Exception { try { Date modifiedSince = request.getHeaderAsDate("If-Modified-Since"); - if (resource.lastModified().getTime() > modifiedSince.getTime() + 1000) { + if (lastModified.getTime() > modifiedSince.getTime() + 1000) { request.respondWith(this); } else { request.respondWith(notModified); @@ -107,12 +116,19 @@ } } - public void respond(Response response) throws Exception { + public void respond(final Response response) throws Exception { + resource.withOptions(this); + if (mimeType == null && fileName != null) { + mimeType = mimeTypeMatcher.mimeTypeFor(fileName); + } response.setHeader("ETag", encode(resource)); response.setHeader("Cache-Control", "public"); response.setHeader("Content-Type", mimeType); - response.setHeader("Last-Modified", resource.lastModified()); - response.setHeader("Expires", monitor.expiresBy()); + response.setHeader("Last-Modified", lastModified); + response.setHeader("Expires", expiresBy); + if (attachement) { + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + } response.writeBodyFrom(resource.open()); } @@ -133,8 +149,7 @@ public void registerRelativeResource(String path, Resource relativeResource) { String pathExpression = (name + path).replaceAll("\\/", "\\/").replaceAll("\\.", "\\."); - String type = mimeTypeMatcher.mimeTypeFor(path); - dispatcher.dispatchOn(".*" + pathExpression + "$", new ResourceServer(type, relativeResource)); + dispatcher.dispatchOn(".*" + pathExpression + "$", new ResourceServer(relativeResource)); } } } Index: component/src/com/icesoft/faces/component/inputrichtext/InputRichText.java =================================================================== --- component/src/com/icesoft/faces/component/inputrichtext/InputRichText.java (revision 16995) +++ component/src/com/icesoft/faces/component/inputrichtext/InputRichText.java Tue Jul 01 21:14:19 EEST 2008 @@ -2,7 +2,6 @@ import com.icesoft.faces.component.CSS_DEFAULT; import com.icesoft.faces.component.ext.taglib.Util; -import com.icesoft.faces.context.ByteArrayResource; import com.icesoft.faces.context.JarResource; import com.icesoft.faces.context.Resource; import com.icesoft.faces.context.ResourceLinker; @@ -12,10 +11,12 @@ import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.util.Date; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -25,6 +26,7 @@ public static final String DEFAULT_RENDERER_TYPE = "com.icesoft.faces.InputRichTextRenderer"; private static final Resource ICE_FCK_EDITOR_JS = new JarResource("com/icesoft/faces/component/inputrichtext/fckeditor_ext.js"); private static final Resource FCK_EDITOR_JS = new JarResource("com/icesoft/faces/component/inputrichtext/fckeditor.js"); + private static final Date lastModified = new Date(); private static final ResourceLinker.Handler FCK_LINKED_BASE = new ResourceLinker.Handler() { public void linkWith(ResourceLinker linker) { try { @@ -33,30 +35,47 @@ ZipEntry entry; while ((entry = zip.getNextEntry()) != null) { if (!entry.isDirectory()) { - String entryName = entry.getName(); - Resource linkedResource = new ByteArrayResource(toByteArray(zip)); - linker.registerRelativeResource(entryName, linkedResource); + final String entryName = entry.getName(); + final byte[] content = toByteArray(zip); + linker.registerRelativeResource(entryName, new Resource() { + public String calculateDigest() { + return String.valueOf(content); - } + } + + public Date lastModified() { + return lastModified; - } + } + + public InputStream open() throws IOException { + return new ByteArrayInputStream(content); + } + + public void withOptions(Resource.Options options) { + options.setFileName(entryName); + options.setLastModified(lastModified); + } + }); + } + } } catch (IOException e) { throw new RuntimeException(e); } } }; - + public static void loadFCKJSIfRequired() { if (FacesContext.getCurrentInstance() != null && baseURI == null && exist.booleanValue()) { ResourceRegistry registry = - (ResourceRegistry) FacesContext.getCurrentInstance(); + (ResourceRegistry) FacesContext.getCurrentInstance(); if (registry != null) { baseURI = registry.loadJavascriptCode(FCK_EDITOR_JS, FCK_LINKED_BASE); registry.loadJavascriptCode(ICE_FCK_EDITOR_JS); } else { //LOG fckeditor's library has not loaded, component will not work as desired } - } + } } - + private String language; private String _for; private String style; @@ -70,7 +89,7 @@ private Boolean disabled = null; private String skin = null; private Boolean saveOnSubmit = null; - + public String getRendererType() { return DEFAULT_RENDERER_TYPE; } @@ -85,7 +104,7 @@ baseURI = null; exist = Boolean.TRUE; } - + public void decode(FacesContext facesContext) { Map map = facesContext.getExternalContext().getRequestParameterMap(); String clientId = getClientId(facesContext); @@ -99,6 +118,7 @@ public void encodeBegin(FacesContext context) throws IOException { super.encodeBegin(context); } + /** *
Set the value of the language
property.
Set the value of the toolbar
property.
Set the value of the customConfigPath
property.
Set the value of the skin
property.
Set the value of the saveOnSubmit
property.