001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/archive/tags/sakai_2-4-1/import-handlers/content-handlers/src/java/org/sakaiproject/importer/impl/handlers/ResourcesHandler.java $
003: * $Id: ResourcesHandler.java 17726 2006-11-01 15:39:28Z lance@indiana.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.importer.impl.handlers;
021:
022: import java.io.ByteArrayInputStream;
023: import java.io.IOException;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.Map;
027: import java.util.Set;
028: import java.util.zip.ZipEntry;
029: import java.util.zip.ZipInputStream;
030:
031: import org.sakaiproject.exception.IdInvalidException;
032: import org.sakaiproject.exception.IdUsedException;
033: import org.sakaiproject.exception.IdUnusedException;
034: import org.sakaiproject.exception.InUseException;
035: import org.sakaiproject.exception.InconsistentException;
036: import org.sakaiproject.exception.OverQuotaException;
037: import org.sakaiproject.exception.PermissionException;
038: import org.sakaiproject.exception.ServerOverloadException;
039: import org.sakaiproject.exception.TypeException;
040: import org.sakaiproject.importer.api.HandlesImportable;
041: import org.sakaiproject.importer.api.Importable;
042: import org.sakaiproject.importer.impl.importables.FileResource;
043: import org.sakaiproject.importer.impl.importables.Folder;
044: import org.sakaiproject.importer.impl.importables.WebLink;
045: import org.sakaiproject.importer.impl.importables.HtmlDocument;
046: import org.sakaiproject.importer.impl.importables.TextDocument;
047: import org.sakaiproject.tool.cover.SessionManager;
048: import org.sakaiproject.component.cover.ServerConfigurationService;
049: import org.sakaiproject.content.api.ContentCollectionEdit;
050: import org.sakaiproject.content.cover.ContentHostingService;
051: import org.sakaiproject.entity.api.ResourceProperties;
052: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
053: import org.sakaiproject.event.api.NotificationService;
054: import org.sakaiproject.util.Validator;
055:
056: import javax.activation.MimetypesFileTypeMap;
057:
058: import org.apache.commons.logging.LogFactory;
059: import org.apache.commons.logging.Log;
060:
061: public class ResourcesHandler implements HandlesImportable {
062: private static final String COPYRIGHT = "(c) 2006";
063:
064: private Log m_log = LogFactory
065: .getLog(org.sakaiproject.importer.impl.handlers.ResourcesHandler.class);
066:
067: public boolean canHandleType(String typeName) {
068: return (("sakai-file-resource".equals(typeName)
069: || ("sakai-folder".equals(typeName))
070: || ("sakai-text-document".equals(typeName))
071: || ("sakai-html-document".equals(typeName))
072: || ("sakai-web-link".equals(typeName)) || ("sakai-learning-module"
073: .equals(typeName))));
074: }
075:
076: public void handle(Importable thing, String siteId) {
077: if (canHandleType(thing.getTypeName())) {
078: String currentUser = SessionManager
079: .getCurrentSessionUserId();
080: SessionManager.getCurrentSession().setUserId("admin");
081: String id = null;
082: String contentType = null;
083: byte[] contents = null;
084: int notifyOption = NotificationService.NOTI_NONE;
085: String title = null;
086: String description = null;
087: Map resourceProps = new HashMap();
088: if ("sakai-file-resource".equals(thing.getTypeName())) {
089: //title = ((FileResource)thing).getTitle();
090: description = ((FileResource) thing).getDescription();
091: String fileName = ((FileResource) thing).getFileName();
092: id = ContentHostingService.getSiteCollection(siteId)
093: + ((FileResource) thing)
094: .getDestinationResourcePath();
095: contentType = new MimetypesFileTypeMap()
096: .getContentType(fileName);
097: contents = ((FileResource) thing).getFileBytes();
098: // if((title == null) || (title.equals(""))) {
099: // title = fileName;
100: // }
101: title = fileName;
102: resourceProps.put(ResourceProperties.PROP_DESCRIPTION,
103: description);
104:
105: if (title.endsWith(".zip")) {
106:
107: //create a folder with the name of the zip, minus the .zip
108: String container = title.substring(0, title
109: .length() - 4);
110: resourceProps.put(
111: ResourceProperties.PROP_DISPLAY_NAME,
112: container);
113:
114: //get the full path to the current folder
115: String path = id.substring(0, id.length()
116: - title.length());
117:
118: addContentCollection(path + container,
119: resourceProps);
120: addAllResources(contents, path + container,
121: notifyOption);
122:
123: } else {
124: if (m_log.isDebugEnabled()) {
125: m_log
126: .debug("import ResourcesHandler about to add file entitled '"
127: + title + "'");
128: }
129: resourceProps
130: .put(ResourceProperties.PROP_DISPLAY_NAME,
131: title);
132: addContentResource(id, contentType, contents,
133: resourceProps, notifyOption);
134: }
135:
136: } else if ("sakai-web-link".equals(thing.getTypeName())) {
137: title = ((WebLink) thing).getTitle();
138: description = ((WebLink) thing).getDescription();
139: id = ContentHostingService.getSiteCollection(siteId)
140: + thing.getContextPath();
141: contentType = ResourceProperties.TYPE_URL;
142: String absoluteUrl = "";
143: if (((WebLink) thing).isAbsolute()) {
144: absoluteUrl = ((WebLink) thing).getUrl();
145: } else {
146: absoluteUrl = ServerConfigurationService
147: .getServerUrl()
148: + "/access/content"
149: + ContentHostingService
150: .getSiteCollection(siteId)
151: + ((WebLink) thing).getUrl();
152: }
153: contents = absoluteUrl.getBytes();
154: if ((title == null) || (title.equals(""))) {
155: title = ((WebLink) thing).getUrl();
156: }
157: resourceProps.put(ResourceProperties.PROP_DISPLAY_NAME,
158: title);
159: resourceProps.put(ResourceProperties.PROP_DESCRIPTION,
160: description);
161: if (m_log.isDebugEnabled()) {
162: m_log
163: .debug("import ResourcesHandler about to add web link entitled '"
164: + title + "'");
165: }
166: addContentResource(id, contentType, contents,
167: resourceProps, notifyOption);
168: } else if ("sakai-html-document"
169: .equals(thing.getTypeName())) {
170: title = ((HtmlDocument) thing).getTitle();
171: contents = ((HtmlDocument) thing).getContent()
172: .getBytes();
173: id = ContentHostingService.getSiteCollection(siteId)
174: + thing.getContextPath();
175: contentType = "text/html";
176: resourceProps.put(ResourceProperties.PROP_DISPLAY_NAME,
177: title);
178: if (m_log.isDebugEnabled()) {
179: m_log
180: .debug("import ResourcesHandler about to add html document entitled '"
181: + title + "'");
182: }
183: addContentResource(id, contentType, contents,
184: resourceProps, notifyOption);
185: } else if ("sakai-text-document"
186: .equals(thing.getTypeName())) {
187: title = ((TextDocument) thing).getTitle();
188: contents = ((TextDocument) thing).getContent()
189: .getBytes();
190: id = ContentHostingService.getSiteCollection(siteId)
191: + thing.getContextPath();
192: contentType = "text/plain";
193: resourceProps.put(ResourceProperties.PROP_DISPLAY_NAME,
194: title);
195: if (m_log.isDebugEnabled()) {
196: m_log
197: .debug("import ResourcesHandler about to add text document entitled '"
198: + title + "'");
199: }
200: addContentResource(id, contentType, contents,
201: resourceProps, notifyOption);
202: } else if ("sakai-folder".equals(thing.getTypeName())) {
203: title = ((Folder) thing).getTitle();
204: description = ((Folder) thing).getDescription();
205: resourceProps.put(ResourceProperties.PROP_DISPLAY_NAME,
206: title);
207: resourceProps.put(ResourceProperties.PROP_DESCRIPTION,
208: description);
209: resourceProps.put(ResourceProperties.PROP_COPYRIGHT,
210: COPYRIGHT);
211: /*
212: * Added title to the end of the path. Otherwise, we're setting the props on the
213: * containing folder rather than the folder itself.
214: */
215: String path = ContentHostingService
216: .getSiteCollection(siteId)
217: + ((Folder) thing).getPath();
218: addContentCollection(path, resourceProps);
219:
220: }
221: SessionManager.getCurrentSession().setUserId(currentUser);
222: }
223:
224: }
225:
226: protected void addAllResources(byte[] archive, String path,
227: int notifyOption) {
228: ZipInputStream zipStream = new ZipInputStream(
229: new ByteArrayInputStream(archive));
230: ZipEntry entry;
231: String contentType;
232: if (path.charAt(0) == '/') {
233: path = path.substring(1);
234: }
235: if (!path.endsWith("/")) {
236: path = path + "/";
237: }
238: try {
239: entry = (ZipEntry) zipStream.getNextEntry();
240: while (entry != null) {
241: Map resourceProps = new HashMap();
242: contentType = new MimetypesFileTypeMap()
243: .getContentType(entry.getName());
244: String title = entry.getName();
245: if (title.lastIndexOf("/") > 0) {
246: title = title.substring(title.lastIndexOf("/") + 1);
247: }
248: resourceProps.put(ResourceProperties.PROP_DISPLAY_NAME,
249: title);
250: resourceProps.put(ResourceProperties.PROP_COPYRIGHT,
251: COPYRIGHT);
252: if (m_log.isDebugEnabled()) {
253: m_log
254: .debug("import ResourcesHandler about to add file entitled '"
255: + title + "'");
256: }
257:
258: int size = (int) entry.getSize();
259: // -1 means unknown size.
260: if (size != -1) {
261:
262: byte[] contents = new byte[(int) size];
263: int returnBytes = 0;
264: int chunk = 0;
265: while (((int) size - returnBytes) > 0) {
266: chunk = zipStream.read(contents, returnBytes,
267: (int) size - returnBytes);
268: if (chunk == -1) {
269: break;
270: }
271: returnBytes += chunk;
272: }
273:
274: if (entry.isDirectory()) {
275:
276: addContentCollection(path + entry.getName(),
277: resourceProps);
278: addAllResources(contents, path
279: + entry.getName(), notifyOption);
280: } else {
281: addContentResource(path + entry.getName(),
282: contentType, contents, resourceProps,
283: notifyOption);
284: }
285: entry = (ZipEntry) zipStream.getNextEntry();
286: } else {
287: if (m_log.isWarnEnabled()) {
288: m_log
289: .warn("Zip file is of unknown size... giving up");
290: }
291: }
292: }
293: } catch (IOException e) {
294: e.printStackTrace();
295: }
296: }
297:
298: protected void addContentResource(String id, String contentType,
299: byte[] contents, Map properties, int notifyOption) {
300: try {
301: id = makeIdClean(id);
302: ResourcePropertiesEdit resourceProps = ContentHostingService
303: .newResourceProperties();
304: Set keys = properties.keySet();
305: for (Iterator i = keys.iterator(); i.hasNext();) {
306: String key = (String) i.next();
307: String value = (String) properties.get(key);
308: resourceProps.addProperty(key, value);
309: }
310: // String enclosingDirectory = id.substring(0, id.lastIndexOf('/', id.length() - 2) + 1);
311: // if(!existsDirectory(enclosingDirectory)) {
312: // Map props = new HashMap();
313: // props.put(ResourceProperties.PROP_DISPLAY_NAME, enclosingDirectory.substring(enclosingDirectory.lastIndexOf('/') + 1, enclosingDirectory.length()));
314: // addContentCollection(enclosingDirectory, props);
315: // }
316: ContentHostingService.addResource(id, contentType,
317: contents, resourceProps, notifyOption);
318: } catch (PermissionException e) {
319: m_log.error("ResourcesHandler.addContentResource: "
320: + e.toString());
321: } catch (IdUsedException e) {
322: // TODO Auto-generated catch block
323: e.printStackTrace();
324: } catch (IdInvalidException e) {
325: // TODO Auto-generated catch block
326: e.printStackTrace();
327: } catch (InconsistentException e) {
328: // TODO Auto-generated catch block
329: e.printStackTrace();
330: } catch (OverQuotaException e) {
331: // TODO Auto-generated catch block
332: e.printStackTrace();
333: } catch (ServerOverloadException e) {
334: // TODO Auto-generated catch block
335: e.printStackTrace();
336: }
337:
338: }
339:
340: protected boolean existsDirectory(String path) {
341: try {
342: ContentHostingService.getCollection(path);
343: } catch (IdUnusedException e) {
344: return false;
345: } catch (TypeException e) {
346: // TODO Auto-generated catch block
347: e.printStackTrace();
348: } catch (PermissionException e) {
349: m_log.error("ResourcesHandler.existsDirectory: "
350: + e.toString());
351: }
352: return true;
353: }
354:
355: protected void addContentCollection(String path, Map properties) {
356: path = makeIdClean(path);
357: ResourcePropertiesEdit resourceProps = ContentHostingService
358: .newResourceProperties();
359: Set keys = properties.keySet();
360: for (Iterator i = keys.iterator(); i.hasNext();) {
361: String key = (String) i.next();
362: String value = (String) properties.get(key);
363: resourceProps.addProperty(key, value);
364: }
365: // ContentCollectionEdit coll = null;
366: try {
367: // String enclosingDirectory = path.substring(0, path.lastIndexOf('/', path.length() - 2) + 1);
368: // if(!existsDirectory(enclosingDirectory)) {
369: // ResourcePropertiesEdit enclosingProps = ContentHostingService.newResourceProperties();
370: // enclosingProps.addProperty(ResourceProperties.PROP_DISPLAY_NAME, );
371: // ContentHostingService.addCollection(enclosingDirectory, enclosingProps);
372: //
373: // }
374:
375: ContentHostingService.addCollection(path, resourceProps);
376: //coll = ContentHostingService.addCollection(path);
377: //ContentHostingService.commitCollection(coll);
378:
379: } catch (IdUsedException e) {
380: // if this thing already exists (which it probably does),
381: // we'll do an update on the properties rather than creating the folder
382: // try {
383: // ContentHostingService.addProperty
384: // (path, ResourceProperties.PROP_DISPLAY_NAME, (String)properties.get(ResourceProperties.PROP_DISPLAY_NAME));
385: // ContentHostingService.addProperty
386: // (path, ResourceProperties.PROP_COPYRIGHT, (String)properties.get(ResourceProperties.PROP_COPYRIGHT));
387: // ContentHostingService.addProperty
388: // (path, ResourceProperties.PROP_DESCRIPTION, (String)properties.get(ResourceProperties.PROP_DESCRIPTION));
389: // } catch (PermissionException e1) {
390: // m_log.error("ResourcesHandler.addContentCollection: " + e.toString());
391: // } catch (IdUnusedException e1) {
392: // // TODO Auto-generated catch block
393: // e1.printStackTrace();
394: // } catch (TypeException e1) {
395: // // TODO Auto-generated catch block
396: // e1.printStackTrace();
397: // } catch (InUseException e1) {
398: // // TODO Auto-generated catch block
399: // e1.printStackTrace();
400: // } catch (ServerOverloadException e1) {
401: // // TODO Auto-generated catch block
402: // e1.printStackTrace();
403: // }
404:
405: } catch (IdInvalidException e) {
406: // TODO Auto-generated catch block
407: e.printStackTrace();
408: } catch (PermissionException e) {
409: // TODO Auto-generated catch block
410: e.printStackTrace();
411: } catch (InconsistentException e) {
412: // TODO Auto-generated catch block
413: e.printStackTrace();
414: }
415: }
416:
417: private String makeIdClean(String path) {
418: String[] parts = path.split("/");
419: String rv = "";
420:
421: for (int i = 0; i < parts.length; i++) {
422: if (parts[i].length() > 0) {
423: rv += "/" + Validator.escapeResourceName(parts[i]);
424: }
425: }
426:
427: return rv;
428: }
429:
430: }
|