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 }