Author: vmassol Date: 2008-02-26 20:41:52 +0100 (Tue, 26 Feb 2008) New Revision: 7975
Added: xwiki-platform/core/branches/xwiki-core-1.3/ xwiki-platform/core/branches/xwiki-core-1.3/pom.xml xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java Removed: xwiki-platform/core/branches/xwiki-core-1.3/pom.xml xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java Log: [maven-release-plugin] copy for branch xwiki-core-1.3 Copied: xwiki-platform/core/branches/xwiki-core-1.3 (from rev 7972, xwiki-platform/core/trunk) Deleted: xwiki-platform/core/branches/xwiki-core-1.3/pom.xml =================================================================== --- xwiki-platform/core/trunk/pom.xml 2008-02-26 17:51:19 UTC (rev 7972) +++ xwiki-platform/core/branches/xwiki-core-1.3/pom.xml 2008-02-26 19:41:52 UTC (rev 7975) @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - * - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * ---> - -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>com.xpn.xwiki.platform</groupId> - <artifactId>xwiki</artifactId> - <version>12-SNAPSHOT</version> - <relativePath>../xwiki-platform-pom</relativePath> - </parent> - <artifactId>xwiki-core-parent</artifactId> - <name>XWiki Platform - Core - Parent POM</name> - <packaging>pom</packaging> - <version>1.3-SNAPSHOT</version> - <description>XWiki Platform - Core - Parent POM</description> - <scm> - <connection>scm:svn:http://svn.xwiki.org/svnroot/xwiki/xwiki-platform/core/trunk</connection> - <developerConnection>scm:svn:https://svn.xwiki.org/svnroot/xwiki/xwiki-platform/core/trunk</developerConnection> - <url>http://svn.xwiki.org/svnroot/xwiki/xwiki-platform/core/trunk</url> - </scm> - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>3.8.2</version> - <scope>test</scope> - </dependency> - </dependencies> - <properties> - <!-- Versions of XWiki dependencies used in Platform/Web modules --> - <platform.tool.verification.version>1.9-SNAPSHOT</platform.tool.verification.version> - </properties> - <modules> - <module>xwiki-core</module> - <module>xwiki-component</module> - <module>xwiki-url</module> - <module>xwiki-containers</module> - <module>xwiki-plexus</module> - <module>xwiki-action</module> - <module>xwiki-velocity</module> - <module>xwiki-observation</module> - </modules> -</project> Copied: xwiki-platform/core/branches/xwiki-core-1.3/pom.xml (from rev 7974, xwiki-platform/core/trunk/pom.xml) =================================================================== --- xwiki-platform/core/branches/xwiki-core-1.3/pom.xml (rev 0) +++ xwiki-platform/core/branches/xwiki-core-1.3/pom.xml 2008-02-26 19:41:52 UTC (rev 7975) @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + * + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>com.xpn.xwiki.platform</groupId> + <artifactId>xwiki</artifactId> + <version>12-SNAPSHOT</version> + <relativePath>../xwiki-platform-pom</relativePath> + </parent> + <artifactId>xwiki-core-parent</artifactId> + <name>XWiki Platform - Core - Parent POM</name> + <packaging>pom</packaging> + <version>1.3-SNAPSHOT</version> + <description>XWiki Platform - Core - Parent POM</description> + <scm> + <connection>scm:svn:http://svn.xwiki.org/svnroot/xwiki/xwiki-platform/core/branches/xwiki-core-1.3</connection> + <developerConnection>scm:svn:https://svn.xwiki.org/svnroot/xwiki/xwiki-platform/core/branches/xwiki-core-1.3</developerConnection> + <url>http://svn.xwiki.org/svnroot/xwiki/xwiki-platform/core/branches/xwiki-core-1.3</url> + </scm> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.2</version> + <scope>test</scope> + </dependency> + </dependencies> + <properties> + <!-- Versions of XWiki dependencies used in Platform/Web modules --> + <platform.tool.verification.version>1.9-SNAPSHOT</platform.tool.verification.version> + </properties> + <modules> + <module>xwiki-core</module> + <module>xwiki-component</module> + <module>xwiki-url</module> + <module>xwiki-containers</module> + <module>xwiki-plexus</module> + <module>xwiki-action</module> + <module>xwiki-velocity</module> + <module>xwiki-observation</module> + </modules> +</project> Deleted: xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java =================================================================== --- xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java 2008-02-26 17:51:19 UTC (rev 7972) +++ xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java 2008-02-26 19:41:52 UTC (rev 7975) @@ -1,329 +0,0 @@ -/* - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - * - */ -package com.xpn.xwiki.web; - -import com.xpn.xwiki.XWiki; -import com.xpn.xwiki.XWikiContext; -import com.xpn.xwiki.XWikiException; -import com.xpn.xwiki.doc.XWikiAttachment; -import com.xpn.xwiki.doc.XWikiDocument; -import com.xpn.xwiki.objects.BaseObject; -import com.xpn.xwiki.util.Util; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.IOException; -import java.util.Date; - -/** - * <p> - * Action for serving skin files. It allows skins to be defined using XDocuments as skins, by - * letting files be placed as text fields in an XWiki.XWikiSkins object, or as attachments to the - * document, or as a file in the filesystem. If the file is not found in the current skin, then it - * is searched in its base skin, and eventually in the default base skins, - * </p> - * <p> - * This action indicates that the results should be publicly cacheable for 30 days. - * </p> - * - * @version $Id: $ - * @since 1.0 - */ -public class SkinAction extends XWikiAction -{ - /** Logging helper. */ - private static final Log LOG = LogFactory.getLog(SkinAction.class); - - /** Path delimiter. */ - private static final String DELIMITER = "/"; - - /** The directory where the skins are placed in the webapp. */ - private static final String SKINS_DIRECTORY = "skins"; - - /** - * [EMAIL PROTECTED] - * - * @see XWikiAction#render(XWikiContext) - */ - public String render(XWikiContext context) throws XWikiException - { - XWiki xwiki = context.getWiki(); - XWikiRequest request = context.getRequest(); - XWikiDocument doc = context.getDoc(); - - String baseskin = xwiki.getBaseSkin(context, true); - XWikiDocument baseskindoc = xwiki.getDocument(baseskin, context); - String defaultbaseskin = xwiki.getDefaultBaseSkin(context); - String path = request.getPathInfo(); - LOG.debug("document: " + doc.getFullName() + " ; baseskin: " + baseskin - + " ; defaultbaseskin: " + defaultbaseskin); - int idx = path.lastIndexOf(DELIMITER); - boolean found = false; - while (idx > 0) { - try { - String filename = Util.decodeURI(path.substring(idx + 1), context); - LOG.debug("Trying '" + filename + "'"); - - if (renderSkin(filename, doc, context)) { - found = true; - break; - } - - if (!doc.getName().equals(baseskin)) { - if (renderSkin(filename, baseskindoc, context)) { - found = true; - break; - } - } - - if (!(doc.getName().equals(defaultbaseskin) || baseskin.equals(defaultbaseskin))) { - // defaultbaseskin can only be on the filesystem, so don't try to use it as a - // skin document. - if (renderSkinFromFilesystem(filename, defaultbaseskin, context)) { - found = true; - break; - } - } - } catch (XWikiException ex) { - if (ex.getCode() == XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION) { - // This means that the response couldn't be sent, although the file was - // successfully found. Signal this further, and stop trying to render. - throw ex; - } - LOG.debug(new Integer(idx), ex); - } - idx = path.lastIndexOf(DELIMITER, idx - 1); - } - if (!found) { - context.getResponse().setStatus(404); - return "docdoesnotexist"; - } - return null; - } - - /** - * Tries to serve a skin file using <tt>doc</tt> as a skin document. The file is searched in - * the following places: - * <ol> - * <li>As the content of a property with the same name as the requested filename, from an - * XWikiSkins object attached to the document.</li> - * <li>As the content of an attachment with the same name as the requested filename.</li> - * <li>As a file located on the filesystem, in the directory with the same name as the current - * document (in case the URL was actually pointing to <tt>/skins/directory/file</tt>.</li> - * </ol> - * - * @param filename The name of the skin file that should be rendered. - * @param doc The skin [EMAIL PROTECTED] XWikiDocument document}. - * @param context The current [EMAIL PROTECTED] XWikiContext request context}. - * @return <tt>true</tt> if the attachment was found and the content was successfully sent. - * @throws XWikiException If the attachment cannot be loaded. - */ - private boolean renderSkin(String filename, XWikiDocument doc, XWikiContext context) - throws XWikiException - { - LOG.debug("Rendering file '" + filename + "' within the '" + doc.getFullName() - + "' document"); - try { - if (doc.isNew()) { - LOG.debug(doc.getName() + " is not a document"); - if (SKINS_DIRECTORY.equals(doc.getSpace())) { - LOG.debug("Trying on the filesystem"); - } - } else { - return renderFileFromObjectField(filename, doc, context) - || renderFileFromAttachment(filename, doc, context) - || (SKINS_DIRECTORY.equals(doc.getSpace()) && renderSkinFromFilesystem( - filename, doc.getName(), context)); - } - } catch (IOException e) { - throw new XWikiException(XWikiException.MODULE_XWIKI_APP, - XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, - "Exception while sending response:", - e); - } - - return renderSkinFromFilesystem(filename, doc.getName(), context); - } - - /** - * Tries to serve a skin file from the filesystem. - * - * @param filename The name of the skin file that should be rendered. - * @param skin The skin name, it should be a subdirectory in <webapp-root>/skins/ - * @param context The current [EMAIL PROTECTED] XWikiContext request context}. - * @return <tt>true</tt> if the file was found and its content was successfully sent. - * @throws XWikiException If the response cannot be sent. - */ - private boolean renderSkinFromFilesystem(String filename, String skin, XWikiContext context) - throws XWikiException - { - LOG.debug("Rendering filesystem file '" + filename + "' from the '" + skin - + "' skin directory"); - XWikiResponse response = context.getResponse(); - String path = DELIMITER + SKINS_DIRECTORY + DELIMITER + skin + DELIMITER + filename; - try { - byte[] data; - data = context.getWiki().getResourceContentAsBytes(path); - if (data != null && data.length > 0) { - String mimetype = context.getEngineContext().getMimeType(filename.toLowerCase()); - if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { - data = context.getWiki().parseContent(new String(data), context).getBytes(); - } - - setupHeaders(response, mimetype, new Date(), data.length); - try { - response.getOutputStream().write(data); - } catch (IOException e) { - throw new XWikiException(XWikiException.MODULE_XWIKI_APP, - XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, - "Exception while sending response", - e); - } - return true; - } - } catch (IOException ex) { - LOG.info("Skin file '" + path + "' does not exist or cannot be accessed"); - } - return false; - } - - /** - * Tries to serve the content of an XWikiSkins object field as a skin file. - * - * @param filename The name of the skin file that should be rendered. - * @param doc The skin [EMAIL PROTECTED] XWikiDocument document}. - * @param context The current [EMAIL PROTECTED] XWikiContext request context}. - * @return <tt>true</tt> if the object exists, and the field is set to a non-empty value, and - * its content was successfully sent. - * @throws IOException If the response cannot be sent. - */ - public boolean renderFileFromObjectField(String filename, XWikiDocument doc, - XWikiContext context) throws IOException - { - LOG.debug("... as object property"); - BaseObject object = doc.getObject("XWiki.XWikiSkins"); - String content = null; - if (object != null) { - content = object.getStringValue(filename); - } - - if (!StringUtils.isBlank(content)) { - XWiki xwiki = context.getWiki(); - XWikiResponse response = context.getResponse(); - String mimetype = xwiki.getEngineContext().getMimeType(filename.toLowerCase()); - if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { - content = context.getWiki().parseContent(content, context); - } - setupHeaders(response, mimetype, doc.getDate(), content.length()); - response.getWriter().write(content); - return true; - } else { - LOG.debug("Object field not found or empty"); - } - return false; - } - - /** - * Tries to serve the content of an attachment as a skin file. - * - * @param filename The name of the skin file that should be rendered. - * @param doc The skin [EMAIL PROTECTED] XWikiDocument document}. - * @param context The current [EMAIL PROTECTED] XWikiContext request context}. - * @return <tt>true</tt> if the attachment was found and its content was successfully sent. - * @throws IOException If the response cannot be sent. - * @throws XWikiException If the attachment cannot be loaded. - */ - public boolean renderFileFromAttachment(String filename, XWikiDocument doc, - XWikiContext context) throws IOException, XWikiException - { - LOG.debug("... as attachment"); - XWikiAttachment attachment = doc.getAttachment(filename); - if (attachment != null) { - XWiki xwiki = context.getWiki(); - XWikiResponse response = context.getResponse(); - byte[] data = attachment.getContent(context); - String mimetype = xwiki.getEngineContext().getMimeType(filename.toLowerCase()); - if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { - data = context.getWiki().parseContent(new String(data), context).getBytes(); - } - setupHeaders(response, mimetype, attachment.getDate(), data.length); - response.getOutputStream().write(data); - return true; - } else { - LOG.debug("Attachment not found"); - } - return false; - } - - /** - * Checks if a mimetype indicates a javascript file. - * - * @param mimetype The mime type to check. - * @return <tt>true</tt> if the mime type represents a javascript file. - */ - public boolean isJavascriptMimeType(String mimetype) - { - boolean result = - "text/javascript".equalsIgnoreCase(mimetype) - || "application/x-javascript".equalsIgnoreCase(mimetype) - || "application/javascript".equalsIgnoreCase(mimetype); - result |= - "application/ecmascript".equalsIgnoreCase(mimetype) - || "text/ecmascript".equalsIgnoreCase(mimetype); - return result; - } - - /** - * Checks if a mimetype indicates a CSS file. - * - * @param mimetype The mime type to check. - * @return <tt>true</tt> if the mime type represents a css file. - */ - public boolean isCssMimeType(String mimetype) - { - return "text/css".equalsIgnoreCase(mimetype); - } - - /** - * Sets several headers to properly identify the response. - * - * @param response The servlet response object, where the headers should be set. - * @param mimetype The mimetype of the file. Used in the "Content-Type" header. - * @param lastChanged The date of the last change of the file. Used in the "Last-Modified" - * header. - * @param length The length of the content (in bytes). Used in the "Content-Length" header. - */ - protected void setupHeaders(XWikiResponse response, String mimetype, Date lastChanged, - int length) - { - if (!StringUtils.isBlank(mimetype)) { - response.setContentType(mimetype); - } else { - response.setContentType("application/octet-stream"); - } - response.setDateHeader("Last-Modified", lastChanged.getTime()); - // Cache for one month (30 days) - response.setHeader("Cache-Control", "public"); - response.setDateHeader("Expires", (new Date()).getTime() + 30 * 24 * 3600 * 1000L); - response.setContentLength(length); - } -} Copied: xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java (from rev 7973, xwiki-platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java) =================================================================== --- xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java (rev 0) +++ xwiki-platform/core/branches/xwiki-core-1.3/xwiki-core/src/main/java/com/xpn/xwiki/web/SkinAction.java 2008-02-26 19:41:52 UTC (rev 7975) @@ -0,0 +1,339 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ +package com.xpn.xwiki.web; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.doc.XWikiAttachment; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.objects.BaseObject; +import com.xpn.xwiki.util.Util; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.util.Date; + +/** + * <p> + * Action for serving skin files. It allows skins to be defined using XDocuments as skins, by + * letting files be placed as text fields in an XWiki.XWikiSkins object, or as attachments to the + * document, or as a file in the filesystem. If the file is not found in the current skin, then it + * is searched in its base skin, and eventually in the default base skins, + * </p> + * <p> + * This action indicates that the results should be publicly cacheable for 30 days. + * </p> + * + * @version $Id: $ + * @since 1.0 + */ +public class SkinAction extends XWikiAction +{ + /** Logging helper. */ + private static final Log LOG = LogFactory.getLog(SkinAction.class); + + /** Path delimiter. */ + private static final String DELIMITER = "/"; + + /** The directory where the skins are placed in the webapp. */ + private static final String SKINS_DIRECTORY = "skins"; + + /** + * [EMAIL PROTECTED] + * + * @see XWikiAction#render(XWikiContext) + */ + public String render(XWikiContext context) throws XWikiException + { + XWiki xwiki = context.getWiki(); + XWikiRequest request = context.getRequest(); + XWikiDocument doc = context.getDoc(); + + String baseskin = xwiki.getBaseSkin(context, true); + XWikiDocument baseskindoc = xwiki.getDocument(baseskin, context); + String defaultbaseskin = xwiki.getDefaultBaseSkin(context); + + String path = request.getPathInfo(); + + if (LOG.isDebugEnabled()) { + LOG.debug("document: " + doc.getFullName() + " ; baseskin: " + baseskin + + " ; defaultbaseskin: " + defaultbaseskin); + } + + int idx = path.lastIndexOf(DELIMITER); + boolean found = false; + while (idx > 0) { + try { + String filename = Util.decodeURI(path.substring(idx + 1), context); + if (LOG.isDebugEnabled()) { + LOG.debug("Trying '" + filename + "'"); + } + + if (renderSkin(filename, doc, context)) { + found = true; + break; + } + + if (!doc.getName().equals(baseskin)) { + if (renderSkin(filename, baseskindoc, context)) { + found = true; + break; + } + } + + if (!(doc.getName().equals(defaultbaseskin) || baseskin.equals(defaultbaseskin))) { + // defaultbaseskin can only be on the filesystem, so don't try to use it as a + // skin document. + if (renderSkinFromFilesystem(filename, defaultbaseskin, context)) { + found = true; + break; + } + } + } catch (XWikiException ex) { + if (ex.getCode() == XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION) { + // This means that the response couldn't be sent, although the file was + // successfully found. Signal this further, and stop trying to render. + throw ex; + } + LOG.debug(new Integer(idx), ex); + } + idx = path.lastIndexOf(DELIMITER, idx - 1); + } + if (!found) { + context.getResponse().setStatus(404); + return "docdoesnotexist"; + } + return null; + } + + /** + * Tries to serve a skin file using <tt>doc</tt> as a skin document. The file is searched in + * the following places: + * <ol> + * <li>As the content of a property with the same name as the requested filename, from an + * XWikiSkins object attached to the document.</li> + * <li>As the content of an attachment with the same name as the requested filename.</li> + * <li>As a file located on the filesystem, in the directory with the same name as the current + * document (in case the URL was actually pointing to <tt>/skins/directory/file</tt>).</li> + * </ol> + * + * @param filename The name of the skin file that should be rendered. + * @param doc The skin [EMAIL PROTECTED] XWikiDocument document}. + * @param context The current [EMAIL PROTECTED] XWikiContext request context}. + * @return <tt>true</tt> if the attachment was found and the content was successfully sent. + * @throws XWikiException If the attachment cannot be loaded. + */ + private boolean renderSkin(String filename, XWikiDocument doc, XWikiContext context) + throws XWikiException + { + if (LOG.isDebugEnabled()) { + LOG.debug("Rendering file '" + filename + "' within the '" + doc.getFullName() + + "' document"); + } + try { + if (doc.isNew()) { + if (LOG.isDebugEnabled()) { + LOG.debug(doc.getName() + " is not a document"); + } + } else { + return renderFileFromObjectField(filename, doc, context) + || renderFileFromAttachment(filename, doc, context) + || (SKINS_DIRECTORY.equals(doc.getSpace()) && renderSkinFromFilesystem( + filename, doc.getName(), context)); + } + } catch (IOException e) { + throw new XWikiException(XWikiException.MODULE_XWIKI_APP, + XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, + "Exception while sending response:", + e); + } + + return renderSkinFromFilesystem(filename, doc.getName(), context); + } + + /** + * Tries to serve a skin file from the filesystem. + * + * @param filename The name of the skin file that should be rendered. + * @param skin The skin name, it should be a subdirectory in <webapp-root>/skins/ + * @param context The current [EMAIL PROTECTED] XWikiContext request context}. + * @return <tt>true</tt> if the file was found and its content was successfully sent. + * @throws XWikiException If the response cannot be sent. + */ + private boolean renderSkinFromFilesystem(String filename, String skin, XWikiContext context) + throws XWikiException + { + if (LOG.isDebugEnabled()) { + LOG.debug("Rendering filesystem file '" + filename + "' from the '" + skin + + "' skin directory"); + } + XWikiResponse response = context.getResponse(); + String path = DELIMITER + SKINS_DIRECTORY + DELIMITER + skin + DELIMITER + filename; + try { + byte[] data; + data = context.getWiki().getResourceContentAsBytes(path); + if (data != null && data.length > 0) { + String mimetype = context.getEngineContext().getMimeType(filename.toLowerCase()); + if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { + data = context.getWiki().parseContent(new String(data), context).getBytes(); + } + + setupHeaders(response, mimetype, new Date(), data.length); + try { + response.getOutputStream().write(data); + } catch (IOException e) { + throw new XWikiException(XWikiException.MODULE_XWIKI_APP, + XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, + "Exception while sending response", + e); + } + return true; + } + } catch (IOException ex) { + LOG.info("Skin file '" + path + "' does not exist or cannot be accessed"); + } + return false; + } + + /** + * Tries to serve the content of an XWikiSkins object field as a skin file. + * + * @param filename The name of the skin file that should be rendered. + * @param doc The skin [EMAIL PROTECTED] XWikiDocument document}. + * @param context The current [EMAIL PROTECTED] XWikiContext request context}. + * @return <tt>true</tt> if the object exists, and the field is set to a non-empty value, and + * its content was successfully sent. + * @throws IOException If the response cannot be sent. + */ + public boolean renderFileFromObjectField(String filename, XWikiDocument doc, + XWikiContext context) throws IOException + { + LOG.debug("... as object property"); + BaseObject object = doc.getObject("XWiki.XWikiSkins"); + String content = null; + if (object != null) { + content = object.getStringValue(filename); + } + + if (!StringUtils.isBlank(content)) { + XWiki xwiki = context.getWiki(); + XWikiResponse response = context.getResponse(); + String mimetype = xwiki.getEngineContext().getMimeType(filename.toLowerCase()); + if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { + content = context.getWiki().parseContent(content, context); + } + setupHeaders(response, mimetype, doc.getDate(), content.length()); + response.getWriter().write(content); + return true; + } else { + LOG.debug("Object field not found or empty"); + } + return false; + } + + /** + * Tries to serve the content of an attachment as a skin file. + * + * @param filename The name of the skin file that should be rendered. + * @param doc The skin [EMAIL PROTECTED] XWikiDocument document}. + * @param context The current [EMAIL PROTECTED] XWikiContext request context}. + * @return <tt>true</tt> if the attachment was found and its content was successfully sent. + * @throws IOException If the response cannot be sent. + * @throws XWikiException If the attachment cannot be loaded. + */ + public boolean renderFileFromAttachment(String filename, XWikiDocument doc, + XWikiContext context) throws IOException, XWikiException + { + LOG.debug("... as attachment"); + XWikiAttachment attachment = doc.getAttachment(filename); + if (attachment != null) { + XWiki xwiki = context.getWiki(); + XWikiResponse response = context.getResponse(); + byte[] data = attachment.getContent(context); + String mimetype = xwiki.getEngineContext().getMimeType(filename.toLowerCase()); + if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { + data = context.getWiki().parseContent(new String(data), context).getBytes(); + } + setupHeaders(response, mimetype, attachment.getDate(), data.length); + response.getOutputStream().write(data); + return true; + } else { + LOG.debug("Attachment not found"); + } + return false; + } + + /** + * Checks if a mimetype indicates a javascript file. + * + * @param mimetype The mime type to check. + * @return <tt>true</tt> if the mime type represents a javascript file. + */ + public boolean isJavascriptMimeType(String mimetype) + { + boolean result = + "text/javascript".equalsIgnoreCase(mimetype) + || "application/x-javascript".equalsIgnoreCase(mimetype) + || "application/javascript".equalsIgnoreCase(mimetype); + result |= + "application/ecmascript".equalsIgnoreCase(mimetype) + || "text/ecmascript".equalsIgnoreCase(mimetype); + return result; + } + + /** + * Checks if a mimetype indicates a CSS file. + * + * @param mimetype The mime type to check. + * @return <tt>true</tt> if the mime type represents a css file. + */ + public boolean isCssMimeType(String mimetype) + { + return "text/css".equalsIgnoreCase(mimetype); + } + + /** + * Sets several headers to properly identify the response. + * + * @param response The servlet response object, where the headers should be set. + * @param mimetype The mimetype of the file. Used in the "Content-Type" header. + * @param lastChanged The date of the last change of the file. Used in the "Last-Modified" + * header. + * @param length The length of the content (in bytes). Used in the "Content-Length" header. + */ + protected void setupHeaders(XWikiResponse response, String mimetype, Date lastChanged, + int length) + { + if (!StringUtils.isBlank(mimetype)) { + response.setContentType(mimetype); + } else { + response.setContentType("application/octet-stream"); + } + response.setDateHeader("Last-Modified", lastChanged.getTime()); + // Cache for one month (30 days) + response.setHeader("Cache-Control", "public"); + response.setDateHeader("Expires", (new Date()).getTime() + 30 * 24 * 3600 * 1000L); + response.setContentLength(length); + } +} _______________________________________________ notifications mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/notifications
