001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017:
018: package org.jpublish;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: import java.io.File;
024: import java.io.FileNotFoundException;
025: import java.io.InputStream;
026: import java.io.OutputStream;
027: import java.util.*;
028:
029: /**
030: * A wrapper around any repository. This wrapper is used to expose the
031: * Repository to the view renderer. The current context is stored when
032: * the wrapper is created which means that the context does not have to
033: * be passed to the <code>get()</code> methods at request-time. Wrapping it
034: * in a Map for making easier the integration with modern template engines
035: * such as: StringTemplate. This is the discussion thread that made me decide
036: * about the implementation:
037: * http://hardlikesoftware.com/weblog/2007/06/25/thoughts-on-stringtemplate-part-2/#comment-1498
038: *
039: * @author Anthony Eden
040: * @author <a href="mailto:florin.patrascu@gmail.com">Florin T.PATRASCU</a>
041: */
042:
043: public class RepositoryWrapper implements Map {
044: public static final String EMPTY_STRING = "";
045: private static final Log log = LogFactory
046: .getLog(RepositoryWrapper.class);
047:
048: private Repository repository;
049: private JPublishContext context;
050:
051: /**
052: * Construct a new RepositoryWrapper over the given repository using
053: * the given context for merging.
054: *
055: * @param repository The repository
056: * @param context The current context
057: */
058: public RepositoryWrapper(Repository repository,
059: JPublishContext context) {
060: this .repository = repository;
061: this .context = context;
062: }
063:
064: /**
065: * Get the content at the given path. Errors will be caught and the
066: * error message will be returned
067: * in place of the content.
068: *
069: * @param path The content path
070: * @return The content as a String
071: */
072: public Object get(Object path) {
073: return this .get((String) path);
074: }
075:
076: /**
077: * Get the content at the given path. The content will be merged
078: * with the associated context.
079: *
080: * @param path The content path
081: * @return The content as a String
082: */
083: public String get(String path) {
084: return get(path, true);
085: }
086:
087: /**
088: * Get the content at the given path, optinally merging it with the
089: * associated context. If merge is true then merging will
090: * occur. Errors will be caught and the error message will be returned
091: * in place of the content.
092: *
093: * @param path The content path
094: * @param merged True to merge
095: * @return The content as a String
096: */
097: public String get(String path, boolean merged) {
098: try {
099: if (merged)
100: return repository.get(path, context);
101: else
102: return repository.get(path);
103:
104: } catch (FileNotFoundException e) {
105: // we really don't need to print the stack trace here
106: log.warn("Page not found: " + path);
107: return e.getMessage();
108:
109: } catch (Exception e) {
110: //e.printStackTrace();
111: String err = path + ", error: " + e.getMessage();
112: log.error(err);
113: return err;
114: }
115: }
116:
117: /**
118: * Get the given content as an InputStream. The InputStream will
119: * return the raw content data. Implementations should not attempt
120: * to pass the data through the view renderer.
121: *
122: * @param path The path to the content
123: * @return The InputStream
124: * @throws Exception if errors occur during the acquisition of the inputstream
125: */
126: public InputStream getInputStream(String path) throws Exception {
127: return repository.getInputStream(path);
128: }
129:
130: /**
131: * Get an OutputStream for writing content to the given path.
132: * Repository implementations are not required to implement this
133: * method if they provide read-only access.
134: *
135: * @param path The path to the content
136: * @return The OutputStream
137: * @throws Exception if errors occur during the acquisition of the outputstream
138: */
139: public OutputStream getOutputStream(String path) throws Exception {
140: return repository.getOutputStream(path);
141: }
142:
143: /**
144: * @return the number of files/directories available in the repository path
145: */
146: public int size() {
147: File file = repository.pathToFile(EMPTY_STRING);
148: int size = 0;
149:
150: if (file.isDirectory()) {
151: size = file.list().length;
152: }
153: return size;
154: }
155:
156: /**
157: * @return true if the repository contains no files/directories
158: */
159: public boolean isEmpty() {
160: return size() == 0;
161: }
162:
163: /**
164: * check if the repository contains the file/directory at the given path
165: *
166: * @param path the path to the content
167: * @return true if the file/directory is found, false otherwise
168: */
169: public boolean containsKey(Object path) {
170: return repository.pathToFile((String) path) != null;
171: }
172:
173: /**
174: * todo: don't know yet the best behavior for this one.
175: *
176: * @param object ideally the pre-rendered content of a page. Tough one.
177: * @return false, for now
178: */
179: public boolean containsValue(Object object) {
180: //can't say :'(
181: //NYI
182: return false;
183: }
184:
185: public Object put(Object key, Object value) {
186: //NYI
187: return null;
188: }
189:
190: /**
191: * if implemented (uncommented), this will delete
192: * the content at the specified path!
193: *
194: * @param path the path to the file or the directory that will be removed
195: * @return null
196: */
197: public Object remove(Object path) {
198: //try {
199: // are you sure???
200: //ok then:
201: //todo: check if is file or directory, then
202: //repository.remove((String) key);
203: //} catch (Exception e) {
204: // e.printStackTrace();
205: //}
206: log.warn("Are you sure you want to remove: " + path + "?????");
207: return null;
208: }
209:
210: public void putAll(Map map) {
211: //NYI
212: }
213:
214: public void clear() {
215: //NYI
216: }
217:
218: /**
219: * Finds all the file/directories names in the repository
220: *
221: * @return a Set containing the file/directory names in the wrapped repository
222: */
223: public Set keySet() {
224: File file = repository.pathToFile(EMPTY_STRING);
225: Set keys = null;
226: try {
227: String[] filesInRepository = file.list();
228: if (filesInRepository != null
229: && filesInRepository.length > 0) {
230: keys = new HashSet(Arrays.asList(filesInRepository));
231: }
232: } catch (Exception e) {
233: e.printStackTrace();
234: }
235: return keys;
236: }
237:
238: public Collection values() {
239: return null;
240: }
241:
242: public Set entrySet() {
243: return null;
244: }
245: }
|