Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/tapestry/asset/AssetExternalizer.java


1   /* $$ Clover has instrumented this file $$ */// Copyright 2004 The Apache Software Foundation
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package org.apache.tapestry.asset;
16  
17  import java.io.File;
18  import java.io.FileOutputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.net.URL;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import javax.servlet.ServletContext;
27  import javax.servlet.http.HttpServlet;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hivemind.ApplicationRuntimeException;
32  import org.apache.hivemind.ClassResolver;
33  import org.apache.tapestry.IRequestCycle;
34  import org.apache.tapestry.Tapestry;
35  import org.apache.tapestry.engine.IPropertySource;
36  import org.apache.tapestry.util.StringSplitter;
37  
38  /**
39   *  Responsible for copying assets from the classpath to an external directory that
40   *  is visible to the web server. The externalizer is stored inside
41   *  the {@link ServletContext} as a named attribute.
42   *
43   *  <p>The externalizer uses the name <code>org.apache.tapestry.AssetExternalizer.<i>application name</i>
44   *  </code>.  It configures itself using two additional 
45   *  properties (searching in 
46   *  {@link org.apache.tapestry.IEngine#getPropertySource()}.
47   *
48   *  <table border=1>
49   *  <tr> <th>Parameter</th> <th>Description</th> </tr>
50   *  <tr valign=top> 
51   *    <td><code>org.apache.tapestry.asset.dir</code> </td>
52   *      <td>The directory to which assets will be copied.</td> </tr>
53   *  <tr valign=top>
54   *    <td><code>org.apache.tapestry.asset.URL</code> </td>
55   *      <td>The corresponding URL for the asset directory.</td> </tr>
56   *  </table>
57   *
58   * <p>If either of these parameters is null, then no externalization occurs.
59   * Private assets will still be available, just less efficiently, as the application
60   * will be invoked via its servlet and, ultimately, the {@link AssetService} will need
61   * to retrieve the asset.
62   *
63   * <p>Assets maintain thier directory structure when copied.  For example,
64   * an asset with a resource path of <code>/com/skunkworx/Banner.gif</code> would
65   * be copied to the file system as <code><i>dir</i>/com/skunkworx/Banner.gif</code> and
66   * would have a URL of <code><i>URL</i>/com/skunkworx/Banner.gif</code>.
67   *
68   * <p>The externalizer will create any directories as needed.
69   *
70   * <p>The externalizer will not overwrite existing files.  When a new version of the application
71   * is deployed with changed assets, there are two deployment stategies:
72   * <ul>
73   * <li>Delete the existing asset directory and allow the externalizer to recreate and
74   * repopulate it.
75   * <li>Change the asset directory and URL, allowing the old and new assets to exist
76   *  side-by-side.
77   * </ul>
78   *
79   * <p>When using the second approach, it is best to use a directory that has
80   * a version number in it, for example, <code>D:/inetpub/assets/0</code> mapped to the URL
81   * <code>/assets/0</code>.  When a new version of the application is deployed, the trailing
82   * version number is incremented from 0 to 1.
83   * 
84   *  @author Howard Lewis Ship
85   * 
86   **/
87  
88  public class AssetExternalizer
89  {public static com.cortexeb.tools.clover.d __CLOVER_36_0 = com.cortexeb.tools.clover.aq.getRecorder(new char[] {67,58,92,119,111,114,107,115,112,97,99,101,92,106,97,107,97,114,116,97,45,116,97,112,101,115,116,114,121,92,102,114,97,109,101,119,111,114,107,92,116,97,114,103,101,116,92,99,108,111,118,101,114,45,100,98},1096998272901L);
90      private static final Log LOG = LogFactory.getLog(AssetExternalizer.class);
91  
92      private ClassResolver _resolver;
93      private File _assetDir;
94      private String _URL;
95  
96      /**
97       *  A map from resource path (as a String) to final URL (as a String).
98       *
99       **/
100 
101     private Map _resources = new HashMap();
102 
103     private static final int BUFFER_SIZE = 2048;
104 
105     protected AssetExternalizer(IRequestCycle cycle)
106     {try { __CLOVER_36_0.M[236]++;
107         __CLOVER_36_0.S[857]++;_resolver = cycle.getEngine().getClassResolver();
108     
109         __CLOVER_36_0.S[858]++;IPropertySource properties = cycle.getEngine().getPropertySource();
110 
111 
112         __CLOVER_36_0.S[859]++;String directory = properties.getPropertyValue("org.apache.tapestry.asset.dir");
113 
114         __CLOVER_36_0.S[860]++;if ((((directory == null) && (++__CLOVER_36_0.CT[174] != 0)) || (++__CLOVER_36_0.CF[174] == 0))){
115             __CLOVER_36_0.S[861]++;return;}
116 
117         __CLOVER_36_0.S[862]++;_URL = properties.getPropertyValue("org.apache.tapestry.asset.URL");
118 
119         __CLOVER_36_0.S[863]++;if ((((_URL == null) && (++__CLOVER_36_0.CT[175] != 0)) || (++__CLOVER_36_0.CF[175] == 0))){
120             __CLOVER_36_0.S[864]++;return;}
121 
122         __CLOVER_36_0.S[865]++;_assetDir = new File(directory);
123 
124         __CLOVER_36_0.S[866]++;LOG.debug("Initialized with directory " + _assetDir + " mapped to " + _URL);
125     } finally { }}
126 
127     protected void externalize(String resourcePath) throws IOException
128     {try { __CLOVER_36_0.M[237]++;
129         __CLOVER_36_0.S[867]++;String[] path;
130         __CLOVER_36_0.S[868]++;int i;
131         __CLOVER_36_0.S[869]++;File file;
132         __CLOVER_36_0.S[870]++;StringSplitter splitter;
133         __CLOVER_36_0.S[871]++;InputStream in;
134         __CLOVER_36_0.S[872]++;OutputStream out;
135         __CLOVER_36_0.S[873]++;int bytesRead;
136         __CLOVER_36_0.S[874]++;URL inputURL;
137         __CLOVER_36_0.S[875]++;byte[] buffer;
138 
139         __CLOVER_36_0.S[876]++;if ((((LOG.isDebugEnabled()) && (++__CLOVER_36_0.CT[176] != 0)) || (++__CLOVER_36_0.CF[176] == 0))){
140             __CLOVER_36_0.S[877]++;LOG.debug("Externalizing " + resourcePath);}
141 
142         __CLOVER_36_0.S[878]++;file = _assetDir;
143 
144         // Resources are always split by the unix seperator, even on Win32.
145 
146         __CLOVER_36_0.S[879]++;splitter = new StringSplitter('/');
147 
148         __CLOVER_36_0.S[880]++;path = splitter.splitToArray(resourcePath);
149 
150         // The path is expected to start with a leading slash, but the StringSplitter
151         // will ignore that leading slash.
152 
153         __CLOVER_36_0.S[881]++;for (i = 0; (((i < path.length - 1) && (++__CLOVER_36_0.CT[177] != 0)) || (++__CLOVER_36_0.CF[177] == 0)); i++){
154         {
155             // Doing it this way makes sure the path seperators are right.
156 
157             __CLOVER_36_0.S[882]++;file = new File(file, path[i]);
158         }}
159 
160         // Make sure the directories exist.
161 
162         __CLOVER_36_0.S[883]++;file.mkdirs();
163 
164         __CLOVER_36_0.S[884]++;file = new File(file, path[path.length - 1]);
165 
166         // If the file exists, then assume all is well.  This is OK for development,
167         // but there may be multithreading (or even multiprocess) race conditions
168         // around the creation of the file.
169 
170         __CLOVER_36_0.S[885]++;if ((((file.exists()) && (++__CLOVER_36_0.CT[178] != 0)) || (++__CLOVER_36_0.CF[178] == 0))){
171             __CLOVER_36_0.S[886]++;return;}
172 
173         // Get the resource and copy it to the file.
174 
175         __CLOVER_36_0.S[887]++;inputURL = _resolver.getResource(resourcePath);
176         __CLOVER_36_0.S[888]++;if ((((inputURL == null) && (++__CLOVER_36_0.CT[179] != 0)) || (++__CLOVER_36_0.CF[179] == 0))){
177             __CLOVER_36_0.S[889]++;throw new IOException(Tapestry.format("missing-resource", resourcePath));}
178 
179         __CLOVER_36_0.S[890]++;in = inputURL.openStream();
180 
181         __CLOVER_36_0.S[891]++;out = new FileOutputStream(file);
182 
183         __CLOVER_36_0.S[892]++;buffer = new byte[BUFFER_SIZE];
184 
185         __CLOVER_36_0.S[893]++;while (true){
186         {
187             __CLOVER_36_0.S[894]++;bytesRead = in.read(buffer, 0, BUFFER_SIZE);
188             __CLOVER_36_0.S[895]++;if ((((bytesRead < 0) && (++__CLOVER_36_0.CT[180] != 0)) || (++__CLOVER_36_0.CF[180] == 0))){
189                 __CLOVER_36_0.S[896]++;break;}
190 
191             __CLOVER_36_0.S[897]++;out.write(buffer, 0, bytesRead);
192         }}
193 
194         __CLOVER_36_0.S[898]++;in.close();
195         __CLOVER_36_0.S[899]++;out.close();
196 
197         // The file is copied!
198     } finally { }}
199 
200     /**
201      *  Gets the externalizer singleton for the application.  If it does not already
202      *  exist, it is created and stored into the {@link ServletContext}.
203      *
204      *  <p>Each Tapestry application within a single {@link ServletContext}
205      *  will have its own externalizer; they are differentiated by the
206      *  application name.
207      *
208      *  @see org.apache.tapestry.spec.ApplicationSpecification#getName()
209      *
210      **/
211 
212     public static AssetExternalizer get(IRequestCycle cycle)
213     {try { __CLOVER_36_0.M[238]++;
214         __CLOVER_36_0.S[900]++;HttpServlet servlet = cycle.getRequestContext().getServlet();
215         __CLOVER_36_0.S[901]++;ServletContext context = servlet.getServletContext();
216 
217         __CLOVER_36_0.S[902]++;String servletName = servlet.getServletName();
218         
219         __CLOVER_36_0.S[903]++;String attributeName = "org.apache.tapestry.AssetExternalizer:" + servletName;
220 
221         __CLOVER_36_0.S[904]++;AssetExternalizer result = (AssetExternalizer) context.getAttribute(attributeName);
222 
223         __CLOVER_36_0.S[905]++;if ((((result == null) && (++__CLOVER_36_0.CT[181] != 0)) || (++__CLOVER_36_0.CF[181] == 0))){
224         {
225             __CLOVER_36_0.S[906]++;result = new AssetExternalizer(cycle);
226             __CLOVER_36_0.S[907]++;context.setAttribute(attributeName, result);
227         }}
228 
229         __CLOVER_36_0.S[908]++;return result;
230     } finally { }}
231 
232     /**
233      *  Gets the URL to a private resource.  If the resource was
234      *  previously copied out of the classpath, the previously
235      *  generated URL is returned.
236      * 
237      *  <p>If the asset directory and URL are not configured, then
238      *  returns null.
239      *
240      *  <p>Otherwise, the asset is copied out to the asset directory,
241      *  the URL is constructed (and recorded for later) and the URL is
242      *  returned.
243      *
244      *  <p>This method is not explicitly synchronized but should work
245      *  multi-threaded.  It synchronizes on the internal
246      *  <code>Map</code> used to map resource paths to URLs.
247      *
248      *  @param resourcePath The full path of the resource within the
249      *  classpath.  This is expected to include a leading slash.  For
250      *  example: <code>/com/skunkworx/Banner.gif</code>.
251      *
252      **/
253 
254     public String getURL(String resourcePath)
255     {try { __CLOVER_36_0.M[239]++;
256         __CLOVER_36_0.S[909]++;String result;
257 
258         __CLOVER_36_0.S[910]++;if ((((_assetDir == null) && (++__CLOVER_36_0.CT[182] != 0)) || (++__CLOVER_36_0.CF[182] == 0))){
259             __CLOVER_36_0.S[911]++;return null;}
260 
261         __CLOVER_36_0.S[912]++;synchronized (_resources)
262         {
263             __CLOVER_36_0.S[913]++;result = (String) _resources.get(resourcePath);
264 
265             __CLOVER_36_0.S[914]++;if ((((result != null) && (++__CLOVER_36_0.CT[183] != 0)) || (++__CLOVER_36_0.CF[183] == 0))){
266                 __CLOVER_36_0.S[915]++;return result;}
267 
268             __CLOVER_36_0.S[916]++;try
269             {
270                 __CLOVER_36_0.S[917]++;externalize(resourcePath);
271             }
272             catch (IOException ex)
273             {
274                 __CLOVER_36_0.S[918]++;throw new ApplicationRuntimeException(
275                     Tapestry.format("AssetExternalizer.externalize-failure", resourcePath, _assetDir),
276                     ex);
277             }
278 
279             __CLOVER_36_0.S[919]++;result = _URL + resourcePath;
280 
281             __CLOVER_36_0.S[920]++;_resources.put(resourcePath, result);
282 
283             __CLOVER_36_0.S[921]++;return result;
284         }
285     } finally { }}
286 }