001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.deployment.cache;
023:
024: import java.util.Map;
025: import java.util.HashMap;
026: import java.util.zip.CRC32;
027:
028: import java.net.URL;
029: import java.net.URLConnection;
030: import java.net.MalformedURLException;
031:
032: import java.io.File;
033: import java.io.FileNotFoundException;
034: import java.io.IOException;
035:
036: import java.io.InputStream;
037: import java.io.OutputStream;
038: import java.io.BufferedInputStream;
039: import java.io.BufferedOutputStream;
040: import java.io.ObjectInputStream;
041: import java.io.ObjectOutputStream;
042: import java.io.FileInputStream;
043: import java.io.FileOutputStream;
044:
045: import org.jboss.system.ServiceMBeanSupport;
046: import org.jboss.system.ConfigurationException;
047: import org.jboss.system.server.ServerConfigLocator;
048:
049: import org.jboss.util.NullArgumentException;
050: import org.jboss.util.NestedRuntimeException;
051: import org.jboss.util.stream.Streams;
052:
053: /**
054: * A local file based {@link DeploymentStore}.
055: *
056: * @jmx:mbean extends="org.jboss.deployment.cache.DeploymentStoreMBean"
057: *
058: * @todo Validate the urlMap
059: *
060: * @version <tt>$Revision: 57205 $</tt>
061: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
062: */
063: public class FileDeploymentStore extends ServiceMBeanSupport implements
064: DeploymentStore, FileDeploymentStoreMBean {
065: /** The local directory where cache data will be stored. */
066: protected File dir;
067:
068: /** The file where the mapping is located. */
069: protected File mapFile;
070:
071: /** The URL to local file mapping. */
072: protected Map urlMap;
073:
074: /**
075: * Set the local directory where cache data will be stored.
076: *
077: * @param dir The local directory where cache data will be stored.
078: *
079: * @throws IOException File not found, not a directory, can't write...
080: *
081: * @jmx:managed-attribute
082: */
083: public void setDirectory(File dir) throws IOException {
084: if (dir == null)
085: throw new NullArgumentException("dir");
086:
087: if (!dir.isAbsolute()) {
088: File serverHome = serverHome = ServerConfigLocator.locate()
089: .getServerHomeDir();
090: dir = new File(serverHome, dir.getPath());
091: }
092:
093: if (!dir.exists()) {
094: if (!dir.mkdirs()) {
095: throw new IOException("Failed to create directory: "
096: + dir);
097: }
098: }
099:
100: if (!dir.isDirectory()) {
101: throw new FileNotFoundException(
102: "Given file reference is not a directory: " + dir);
103: }
104:
105: if (!dir.canWrite()) {
106: throw new IOException("Can not write to directory: " + dir);
107: }
108:
109: if (!dir.canRead()) {
110: throw new IOException("Can not read directory: " + dir);
111: }
112:
113: // should be ok...
114:
115: this .dir = dir.getCanonicalFile();
116:
117: log.debug("Using directory for cache storage: " + dir);
118:
119: // the map file to use
120: this .mapFile = new File(dir, "state-map.ser");
121: }
122:
123: /**
124: * Returns the local directory where cache data is stored.
125: *
126: * @return The local directory where cache data is stored.
127: *
128: * @jmx:managed-attribute
129: */
130: public File getDirectory() {
131: return this .dir;
132: }
133:
134: /**
135: * Set the name of the local directory where cache data will be stored.
136: *
137: * <p>Invokes {@link #setDirectory}.
138: *
139: * @param dirname The name of the local directory where cache data will be stored.
140: *
141: * @throws IOException File not found, not a directory, can't write...
142: *
143: * @jmx:managed-attribute
144: */
145: public void setDirectoryName(String dirname) throws IOException {
146: if (dirname == null)
147: throw new NullArgumentException("dirname");
148:
149: setDirectory(new File(dirname));
150: }
151:
152: /**
153: * Get the name of the local directory where cache data is stored.
154: *
155: * @return The name of the local directory where cache data is stored.
156: *
157: * @jmx:managed-attribute
158: */
159: public String getDirectoryName() {
160: return dir.getAbsolutePath();
161: }
162:
163: /////////////////////////////////////////////////////////////////////////
164: // DeploymentStore //
165: /////////////////////////////////////////////////////////////////////////
166:
167: protected URL getURLFromFile(final File file) {
168: try {
169: return file.toURL();
170: } catch (Exception e) {
171: // should never happen
172: throw new NestedRuntimeException(e);
173: }
174: }
175:
176: public URL get(final URL url) {
177: File file = (File) urlMap.get(url);
178: if (file == null)
179: return null;
180:
181: return getURLFromFile(file);
182: }
183:
184: public URL put(final URL url) throws Exception {
185: URL localURL = get(url);
186: File file;
187:
188: if (localURL == null) {
189: // make a short unique filename for the given url which
190: // will always be generated for this specific url
191: CRC32 checksum = new CRC32();
192: checksum.update(url.toString().getBytes());
193:
194: String prefix = Long.toString(checksum.getValue(),
195: Character.MAX_RADIX);
196: String filename = url.getFile();
197: filename = filename.substring(
198: filename.lastIndexOf("/") + 1, filename.length());
199:
200: file = new File(dir, prefix + "-" + filename);
201: urlMap.put(url, file);
202: writeMap();
203: } else {
204: // no need to regen the filename, we have it already
205: file = (File) urlMap.get(url);
206: }
207:
208: // copy the data from the url to the local file
209: copyURL(url, file);
210:
211: // return the local file url
212: return getURLFromFile(file);
213: }
214:
215: /**
216: * Copy the data at the given source URL to the given file.
217: */
218: protected void copyURL(final URL source, final File dest)
219: throws IOException {
220: InputStream is = new BufferedInputStream(source
221: .openConnection().getInputStream());
222: OutputStream os = new BufferedOutputStream(
223: new FileOutputStream(dest));
224:
225: try {
226: Streams.copy(is, os);
227: os.flush();
228: } finally {
229: os.close();
230: is.close();
231: }
232: }
233:
234: /**
235: * Read the url map from serialized state.
236: */
237: protected Map readMap() throws ClassNotFoundException, IOException {
238: if (mapFile.exists()) {
239: Map map;
240:
241: InputStream is = new BufferedInputStream(
242: new FileInputStream(mapFile));
243: ObjectInputStream ois = new ObjectInputStream(is);
244:
245: try {
246: map = (Map) ois.readObject();
247: } finally {
248: ois.close();
249: }
250:
251: return map;
252: } else {
253: log.debug("Map file not found, creating new map");
254: return new HashMap();
255: }
256: }
257:
258: /**
259: * Write the url map to serialized state.
260: */
261: protected void writeMap() throws IOException {
262: OutputStream os = new BufferedOutputStream(
263: new FileOutputStream(mapFile));
264: ObjectOutputStream oos = new ObjectOutputStream(os);
265:
266: try {
267: oos.writeObject(urlMap);
268: oos.flush();
269: } finally {
270: oos.close();
271: }
272: }
273:
274: /////////////////////////////////////////////////////////////////////////
275: // Service/ServiceMBeanSupport //
276: /////////////////////////////////////////////////////////////////////////
277:
278: /**
279: * Setup the url map.
280: */
281: protected void createService() throws Exception {
282: if (dir == null)
283: throw new ConfigurationException(
284: "Missing attribute 'Directory'");
285:
286: // read the map if there is one
287: urlMap = readMap();
288: }
289: }
|