001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.decoration;
018:
019: import java.io.File;
020: import java.io.Serializable;
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.net.URLClassLoader;
024: import java.util.Collections;
025: import java.util.List;
026: import java.util.Locale;
027: import java.util.MissingResourceException;
028: import java.util.Properties;
029: import java.util.ResourceBundle;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.apache.jetspeed.util.Path;
034:
035: /**
036: * Base class implementing the most common methods shared between
037: * LayoutDecorations and PortletDecorations.
038: *
039: *
040: * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
041: * @author <a href="mailto:smilek@apache.org">Steve Milek</a>
042: *
043: * @see org.apache.jetspeed.decoration.Decoration
044: * @see org.apache.jetspeed.decoration.LayoutDecoration
045: * @see org.apache.jetspeed.decoration.PortletDecoration
046: *
047: */
048: public class BaseDecoration implements Decoration, Serializable {
049: private static final Log log = LogFactory
050: .getLog(BaseDecoration.class);
051:
052: protected static final String NO_SUCH_RESOURCE = "no_such_resource";
053: protected transient Properties config;
054: private transient ResourceValidator validator;
055: private final String name;
056: private final Path basePath;
057: private final Path baseClientPath;
058: private transient PathResolverCache cache;
059: private final String commonStylesheet;
060: private final String portalStylesheet;
061: private final String desktopStylesheet;
062: private List actions;
063: private String currentModeAction;
064: private String currentStateAction;
065: private boolean supportsDesktop;
066:
067: /**
068: *
069: * @param config <code>java.util.Properties</code> object containing configuration infomation
070: * for this Decoration.
071: * @param validator The ResourceValidator to be used in looking up fully-qualified resource pathes
072: * @param baseClientPath The "root" of the decroation hierarchy.
073: *
074: * @throws InvalidDecorationConfigurationException
075: */
076: public BaseDecoration(Properties config,
077: ResourceValidator validator, Path basePath,
078: Path baseClientPath, PathResolverCache cache) {
079: this .config = config;
080: this .validator = validator;
081: this .basePath = basePath;
082: this .baseClientPath = baseClientPath;
083: this .cache = cache;
084:
085: this .name = config.getProperty("name");
086:
087: this .commonStylesheet = config.getProperty("stylesheet",
088: DEFAULT_COMMON_STYLE_SHEET);
089:
090: this .supportsDesktop = "true".equalsIgnoreCase(config
091: .getProperty(Decoration.DESKTOP_SUPPORTED_PROPERTY));
092: if (this .supportsDesktop) {
093: this .portalStylesheet = config.getProperty(
094: "stylesheet.portal", DEFAULT_PORTAL_STYLE_SHEET);
095: this .desktopStylesheet = config.getProperty(
096: "stylesheet.desktop", DEFAULT_DESKTOP_STYLE_SHEET);
097: } else {
098: this .portalStylesheet = null;
099: this .desktopStylesheet = null;
100: }
101:
102: if (log.isDebugEnabled()) {
103: log
104: .debug("BaseDecoration basePath: "
105: + basePath.toString());
106: log.debug("BaseDecoration baseClientPath: "
107: + baseClientPath.toString());
108: }
109: }
110:
111: public void init(Properties config, ResourceValidator validator,
112: PathResolverCache cache) {
113: this .config = config;
114: this .validator = validator;
115: this .cache = cache;
116: }
117:
118: public String getName() {
119: return name;
120: }
121:
122: public String getBasePath() {
123: return basePath.toString();
124: }
125:
126: public String getBasePath(String relativePath) {
127: if (relativePath == null) {
128: return basePath.toString();
129: }
130: return basePath.addSegment(relativePath).toString();
131: }
132:
133: public String getResource(String path) {
134: Path workingPath = baseClientPath.getChild(path);
135:
136: String hit = cache.getPath(workingPath.toString());
137: if (hit != null) {
138: return hit;
139: } else {
140: String locatedPath = getResource(baseClientPath, new Path(
141: path));
142: if (!locatedPath.startsWith(NO_SUCH_RESOURCE)) {
143: if (!path.startsWith("/")) {
144: locatedPath = locatedPath.substring(1);
145: }
146: cache.addPath(workingPath.toString(), locatedPath);
147: return locatedPath;
148: }
149: }
150: return null;
151: }
152:
153: /**
154: * Recursively tries to locate a resource.
155: *
156: * @param rootPath initial path to start looking for the <code>searchPath.</code>
157: * The "pruning" of the rootPath of subsequest recursive calls follows the logic
158: * detailed in the {@link Decoration#getResource(String)} method.
159: * @param searchPath relative path to the resource we wish to locate.
160: * @return
161: *
162: * @see Decoration
163: */
164: protected String getResource(Path rootPath, Path searchPath) {
165: String pathString = rootPath.getChild(searchPath).toString();
166: if (validator.resourceExists(pathString)) {
167: return pathString;
168: } else if (rootPath.length() > 0) {
169:
170: return getResource(rootPath.removeLastPathSegment(),
171: searchPath);
172: } else {
173: return NO_SUCH_RESOURCE + searchPath.getFileExtension();
174: }
175: }
176:
177: public String getStyleSheet() {
178: if (this .commonStylesheet != null) {
179: return getResource(this .commonStylesheet);
180: }
181: return null;
182: }
183:
184: public String getStyleSheetPortal() {
185: if (this .portalStylesheet != null) {
186: return getResource(this .portalStylesheet);
187: }
188: return null;
189: }
190:
191: public String getStyleSheetDesktop() {
192: if (this .desktopStylesheet != null) {
193: return getResource(this .desktopStylesheet);
194: }
195: return null;
196: }
197:
198: public List getActions() {
199: if (actions != null) {
200: return actions;
201: } else {
202: return Collections.EMPTY_LIST;
203: }
204: }
205:
206: public void setActions(List actions) {
207: this .actions = actions;
208: }
209:
210: public String getProperty(String name) {
211: return config.getProperty(name);
212: }
213:
214: public String getBaseCSSClass() {
215: return config.getProperty(Decoration.BASE_CSS_CLASS_PROP,
216: getName());
217: }
218:
219: public String getCurrentModeAction() {
220: return this .currentModeAction;
221: }
222:
223: public void setCurrentModeAction(String currentModeAction) {
224: this .currentModeAction = currentModeAction;
225: }
226:
227: public String getCurrentStateAction() {
228: return this .currentStateAction;
229: }
230:
231: public void setCurrentStateAction(String currentStateAction) {
232: this .currentStateAction = currentStateAction;
233: }
234:
235: public String getResourceBundleName() {
236: return config.getProperty(Decoration.RESOURCE_BUNDLE_PROP);
237: }
238:
239: public ResourceBundle getResourceBundle(Locale locale,
240: org.apache.jetspeed.request.RequestContext context) {
241: String resourceDirName = context.getConfig()
242: .getServletContext().getRealPath(
243: getResource(RESOURCES_DIRECTORY_NAME));
244: File resourceDir = new File(resourceDirName);
245: String resourceName = getResourceBundleName();
246: if (resourceName == null) {
247: throw new NullPointerException(
248: "Decoration cannot get ResourceBundle due to null value for decoration property "
249: + Decoration.RESOURCE_BUNDLE_PROP + ".");
250: }
251: if (!resourceDir.isDirectory()) {
252: throw new MissingResourceException(
253: "Can't find the resource directory: "
254: + resourceDirName, resourceName + "_"
255: + locale, "");
256: }
257: URL[] urls = new URL[1];
258: try {
259: urls[0] = resourceDir.toURL();
260: } catch (MalformedURLException e) {
261: throw new MissingResourceException(
262: "The resource directory cannot be parsed as a URL: "
263: + resourceDirName, resourceName + "_"
264: + locale, "");
265: }
266: return ResourceBundle.getBundle(resourceName, locale,
267: new URLClassLoader(urls));
268: }
269:
270: public boolean supportsDesktop() {
271: return this.supportsDesktop;
272: }
273: }
|