View Javadoc

1   package org.apache.turbine.services.xmlrpc.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.BufferedReader;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileWriter;
26  import java.io.IOException;
27  import java.io.InputStreamReader;
28  import java.io.StringWriter;
29  
30  import javax.mail.internet.MimeUtility;
31  
32  import org.apache.commons.lang.StringUtils;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  import org.apache.turbine.Turbine;
38  
39  import org.apache.turbine.services.servlet.TurbineServlet;
40  
41  /***
42   * A Handler for use with the XML-RPC service that will deal
43   * with clients sending file to the server (Turbine application)
44   * and clients getting files from the server (Turbine application).
45   *
46   * 1) In the first case where the client sends a file to the server,
47   * the client has encoded the file contents and passes those
48   * encoded file contents on to the server:
49   *
50   * Client --------> encoded file contents -------------> Server
51   *
52   * The server must then decode the file contents and write the
53   * decoded file contents to disk.
54   *
55   * 2) In the second case where the client gets a file from the
56   * the server, the server has encoded the file contents and
57   * passes those encoded file contents on to the client:
58   *
59   * Client <-------  encoded file contents <------------- Server
60   *
61   * The client must then decode the file contents and write the
62   * decoded file contents to disk.
63   *
64   * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
65   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
66   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
67   * @version $Id: FileHandler.java 534527 2007-05-02 16:10:59Z tv $
68   * @deprecated This is not scope of the Service itself but of an
69   *             application which uses the service. This class shouldn't
70   *             be part of Turbine but of an addon application.
71   */
72  public class FileHandler
73  {
74      /*** Logging */
75      private static Log log = LogFactory.getLog(FileHandler.class);
76  
77      /***
78       * Default Constructor
79       */
80      public FileHandler()
81      {
82      }
83  
84      /***
85       * The client has indicated that it would like
86       * to send a file to the server and have it
87       * stored in a certain location on the server.
88       *
89       * So a client Turbine application might use the
90       * following bit of code to send a file to a server
91       * Turbine application:
92       *
93       * TurbineXmlRpc.executeRpc("file.send", params)
94       *
95       * Where:
96       *
97       * params.get(0) = contents of the file as a string.
98       * params.get(1) = the name the file should have when it lands.
99       * params.get(2) = property describing where the file should land.
100      *
101      * @param fileContents The contents of the file to store. It
102      *    is assumed that any xml content is properly encoded!
103      *
104      * @param fileName Name to give the file created to store
105      *    the contents.
106      *
107      * @param targetLocationProperty storage location of this file
108      *    is controlled by this property that is specified in
109      *    the TR.props file or an included properties file.
110      */
111     public boolean send(String fileContents,
112                         String targetLocationProperty,
113                         String fileName)
114     {
115         /*
116          * Simply take the file contents that have been sent
117          * by the client and write them to disk in the
118          * specified location: targetLocationProperty specifies
119          * the directory in which to place the fileContents
120          * with the name fileName.
121          */
122         return writeFileContents(fileContents, targetLocationProperty,
123                 fileName);
124     }
125 
126     /***
127      * The client has indicated that it would like
128      * to get a file from the server.
129      *
130      * So a client Turbine application might use the
131      * following bit of code to get a file from a server
132      * Turbine application:
133      *
134      * TurbineXmlRpc.executeRpc("file.get", params)
135      *
136      * Where:
137      *
138      * params.get(0) = the name the file should have when it lands.
139      * params.get(1) = property describing where the file should land.
140      *
141      * @param fileName Name to give the file created to store
142      *    the contents.
143      *
144      * @param targetLocationProperty storage location of this file
145      *    is controlled by this property that is specified in
146      *    the TR.props file or an included properties file.
147      *
148      * @return the file contents encoded with base64.
149      */
150     public String get(String targetLocationProperty,
151                       String fileName)
152     {
153         /*
154          * Place the contents of the file with the name
155          * fileName in the directory specified by
156          * targetLocationProperty.
157          */
158         return readFileContents(targetLocationProperty, fileName);
159     }
160 
161     /***
162      * Return the content of file encoded for transfer
163      *
164      * @param targetLocationProperty path to file to encode.
165      * @param fileName file to encode
166      * @return String encoded contents of the requested file.
167      */
168     public static String readFileContents(String targetLocationProperty,
169                                           String fileName)
170     {
171         String location =
172           Turbine.getConfiguration().getString(targetLocationProperty);
173 
174         if (StringUtils.isEmpty(location))
175         {
176           log.error("Could not load Property for location "
177               + targetLocationProperty);
178           return null;
179         }
180 
181         File tmpF = new File(".");
182 
183         StringBuffer sb = new StringBuffer();
184         sb.append(location);
185         sb.append(File.separator);
186         sb.append(fileName);
187 
188         String file = TurbineServlet.getRealPath(sb.toString());
189 
190         StringWriter sw = null;
191         BufferedReader reader = null;
192         try
193         {
194             /*
195              * This little routine was borrowed from the
196              * velocity ContentResource class.
197              */
198 
199             sw = new StringWriter();
200 
201             reader = new BufferedReader(
202                     new InputStreamReader(
203                             new FileInputStream(file)));
204 
205             char buf[] = new char[1024];
206             int len = 0;
207 
208             while ((len = reader.read(buf, 0, 1024)) != -1)
209             {
210                 sw.write(buf, 0, len);
211             }
212 
213             return MimeUtility.encodeText(sw.toString(), "UTF-8", "B");
214         }
215         catch (IOException ioe)
216         {
217             log.error("[FileHandler] Unable to encode the contents " +
218                     "of the request file.", ioe);
219 
220             return null;
221         }
222         finally
223         {
224             try
225             {
226                 if (sw != null)
227                 {
228                     sw.close();
229                 }
230                 if (reader != null)
231                 {
232                     reader.close();
233                 }
234             }
235             catch (Exception e)
236             {
237             }
238         }
239     }
240 
241     public static boolean writeFileContents(String fileContents,
242                                             String targetLocationProperty,
243                                             String fileName)
244     {
245         String location =
246           Turbine.getConfiguration().getString(targetLocationProperty);
247 
248         if (StringUtils.isEmpty(location))
249         {
250           log.error("Could not load Property for location "
251               + targetLocationProperty);
252           return false;
253         }
254 
255         /*
256          * The target location is always within the webapp to
257          * make the application fully portable. So use the TurbineServlet
258          * service to map the target location in the webapp space.
259          */
260 
261         File targetLocation = new File(
262             TurbineServlet.getRealPath(location));
263 
264         if (!targetLocation.exists())
265         {
266             /*
267              * If the target location doesn't exist then
268              * attempt to create the target location and any
269              * necessary parent directories as well.
270              */
271             if (!targetLocation.mkdirs())
272             {
273                 log.error("[FileHandler] Could not create target location: " +
274                         targetLocation + ". Cannot transfer file from client.");
275 
276                 return false;
277             }
278             else
279             {
280                 log.info("[FileHandler] Creating target location:" +
281                         targetLocation +
282                         " in order to complete file transfer from client.");
283             }
284         }
285 
286         FileWriter fileWriter = null;
287         try
288         {
289             /*
290              * Try to create the target file and write it out
291              * to the target location.
292              */
293             fileWriter = new FileWriter(
294                     targetLocation + "/" + fileName);
295 
296             /*
297              * It is assumed that the file has been encoded
298              * and therefore must be decoded before the
299              * contents of the file are stored to disk.
300              */
301             fileWriter.write(MimeUtility.decodeText(fileContents));
302 
303             return true;
304         }
305         catch (IOException ioe)
306         {
307             log.error("[FileHandler] Could not write the decoded file " +
308                     "contents to disk for the following reason.", ioe);
309 
310             return false;
311         }
312         finally
313         {
314             try
315             {
316                 if (fileWriter != null)
317                 {
318                     fileWriter.close();
319                 }
320             }
321             catch (Exception e)
322             {
323             }
324         }
325     }
326 
327     /***
328      * Method to allow a client to remove a file from
329      * the server
330      *
331      * @param sourceLocationProperty
332      * @param sourceFileName
333      */
334     public static void remove(String sourceLocationProperty,
335                               String sourceFileName)
336     {
337         String location =
338           Turbine.getConfiguration().getString(sourceLocationProperty);
339 
340         if (StringUtils.isEmpty(location))
341         {
342           log.error("Could not load Property for location "
343               + sourceLocationProperty);
344           return;
345         }
346 
347         /*
348          * The target location is always within the webapp to
349          * make the application fully portable. So use the TurbineServlet
350          * service to map the target location in the webapp space.
351          */
352         File sourceFile =
353             new File(TurbineServlet.getRealPath(sourceLocationProperty
354                          + "/" + sourceFileName));
355 
356         if (sourceFile.exists())
357         {
358             sourceFile.delete();
359         }
360     }
361 }