View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.web.jcr.rest.client.json;
25  
26  import java.io.File;
27  import java.io.FileInputStream;
28  import java.net.URL;
29  import java.text.SimpleDateFormat;
30  import java.util.Calendar;
31  import java.util.TimeZone;
32  import net.jcip.annotations.Immutable;
33  import org.codehaus.jettison.json.JSONObject;
34  import org.modeshape.common.util.Base64;
35  import org.modeshape.common.util.CheckArg;
36  import org.modeshape.web.jcr.rest.client.IJcrConstants;
37  import org.modeshape.web.jcr.rest.client.Utils;
38  import org.modeshape.web.jcr.rest.client.domain.Workspace;
39  
40  /**
41   * The <code>FileNode</code> class is responsible for knowing how to create a URL for a file, create a JSON representation of a
42   * file, and to create the appropriate JCR nodes for a file.
43   */
44  @Immutable
45  public final class FileNode extends JsonNode {
46  
47      // ===========================================================================================================================
48      // Fields
49      // ===========================================================================================================================
50  
51      /**
52       * The file on the local file system.
53       */
54      private final File file;
55  
56      /**
57       * The folder in the workspace where the file is or will be published or unpublished.
58       */
59      private final String path;
60  
61      /**
62       * The workspace where the file is or will be published or unpublished.
63       */
64      private final Workspace workspace;
65  
66      // ===========================================================================================================================
67      // Constructors
68      // ===========================================================================================================================
69  
70      /**
71       * @param workspace the workspace being used (never <code>null</code>)
72       * @param path the path in the workspace (never <code>null</code>)
73       * @param file the file on the local file system (never <code>null</code>)
74       * @throws Exception if there is a problem constructing the file node
75       */
76      public FileNode( Workspace workspace,
77                       String path,
78                       File file ) throws Exception {
79          super(file.getName());
80  
81          CheckArg.isNotNull(workspace, "workspace");
82          CheckArg.isNotNull(path, "path");
83  
84          this.file = file;
85          this.path = path;
86          this.workspace = workspace;
87  
88          // add properties
89          JSONObject properties = new JSONObject();
90          put(IJsonConstants.PROPERTIES_KEY, properties);
91          properties.put(IJcrConstants.PRIMARY_TYPE_PROPERTY, IJcrConstants.FILE_NODE_TYPE);
92  
93          // add children
94          JSONObject children = new JSONObject();
95          put(IJsonConstants.CHILDREN_KEY, children);
96  
97          // add content child
98          JSONObject kid = new JSONObject();
99          children.put(IJcrConstants.CONTENT_PROPERTY, kid);
100 
101         // add child properties
102         properties = new JSONObject();
103         kid.put(IJsonConstants.PROPERTIES_KEY, properties);
104         properties.put(IJcrConstants.PRIMARY_TYPE_PROPERTY, IJcrConstants.RESOURCE_NODE_TYPE);
105 
106         // add required jcr:lastModified property
107         Calendar lastModified = Calendar.getInstance();
108         lastModified.setTimeInMillis(file.lastModified());
109         SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
110         formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
111         properties.put(IJcrConstants.LAST_MODIFIED, formatter.format(lastModified.getTime()));
112 
113         // add required jcr:mimeType property (just use a default value)
114         properties.put(IJcrConstants.MIME_TYPE, Utils.getMimeType(file));
115     }
116 
117     // ===========================================================================================================================
118     // Methods
119     // ===========================================================================================================================
120 
121     /**
122      * {@inheritDoc}
123      * 
124      * @see org.modeshape.web.jcr.rest.client.json.JsonNode#getContent()
125      */
126     @Override
127     public byte[] getContent() throws Exception {
128         // add required jcr:data property (do this lazily only when the content is requested)
129         JSONObject children = (JSONObject)get(IJsonConstants.CHILDREN_KEY);
130         JSONObject kid = (JSONObject)children.get(IJcrConstants.CONTENT_PROPERTY);
131         JSONObject props = (JSONObject)kid.get(IJsonConstants.PROPERTIES_KEY);
132         props.put(IJcrConstants.DATA_PROPERTY, readFile());
133 
134         return super.getContent();
135     }
136 
137     /**
138      * Note: Currently used for testing only.
139      * 
140      * @param jsonResponse the JSON response obtained from performing a GET using the file content URL
141      * @return the encoded file contents
142      * @throws Exception if there is a problem obtaining the contents
143      * @see #getFileContentsUrl()
144      */
145     String getFileContents( String jsonResponse ) throws Exception {
146         CheckArg.isNotNull(jsonResponse, "jsonResponse");
147         JSONObject contentNode = new JSONObject(jsonResponse);
148         JSONObject props = (JSONObject)contentNode.get(IJsonConstants.PROPERTIES_KEY);
149         String encodedContents = props.getString(IJcrConstants.DATA_PROPERTY);
150         return encodedContents;
151     }
152 
153     /**
154      * Note: Currently used for testing only.
155      * 
156      * @return the URL that can be used to obtain the encoded file contents from a workspace
157      * @throws Exception if there is a problem constructing the URL
158      */
159     URL getFileContentsUrl() throws Exception {
160         StringBuilder url = new StringBuilder(getUrl().toString());
161         url.append('/').append(IJcrConstants.CONTENT_PROPERTY);
162         return new URL(url.toString());
163     }
164 
165     /**
166      * @return the path where the file is or will be published or unpublished
167      */
168     public String getPath() {
169         return this.path;
170     }
171 
172     /**
173      * {@inheritDoc}
174      * 
175      * @see org.modeshape.web.jcr.rest.client.json.JsonNode#getUrl()
176      */
177     @Override
178     public URL getUrl() throws Exception {
179         FolderNode folderNode = new FolderNode(this.workspace, getPath());
180         StringBuilder url = new StringBuilder(folderNode.getUrl().toString());
181 
182         // add file to path and encode the name
183         url.append('/').append(JsonUtils.encode(this.file.getName()));
184         return new URL(url.toString());
185     }
186 
187     /**
188      * @return the base 64 encoded file content
189      * @throws Exception if there is a problem reading the file
190      */
191     String readFile() throws Exception {
192         return Base64.encode(new FileInputStream(this.file.getAbsoluteFile()));
193     }
194 
195 }