001: /*
002: * CreativeCommons.java
003: *
004: * Version: $Revision: 2314 $
005: *
006: * Date: $Date: 2007-11-06 16:28:48 -0600 (Tue, 06 Nov 2007) $
007: *
008: * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
009: * Institute of Technology. All rights reserved.
010: *
011: * Redistribution and use in source and binary forms, with or without
012: * modification, are permitted provided that the following conditions are
013: * met:
014: *
015: * - Redistributions of source code must retain the above copyright
016: * notice, this list of conditions and the following disclaimer.
017: *
018: * - Redistributions in binary form must reproduce the above copyright
019: * notice, this list of conditions and the following disclaimer in the
020: * documentation and/or other materials provided with the distribution.
021: *
022: * - Neither the name of the Hewlett-Packard Company nor the name of the
023: * Massachusetts Institute of Technology nor the names of their
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
030: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
032: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
033: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
034: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
036: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
037: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
038: * DAMAGE.
039: */
040: package org.dspace.license;
041:
042: import java.io.InputStream;
043: import java.io.ByteArrayInputStream;
044: import java.io.ByteArrayOutputStream;
045: import java.io.IOException;
046: import java.io.StringWriter;
047: import java.net.URL;
048: import java.net.URLConnection;
049: import java.sql.SQLException;
050:
051: import javax.xml.transform.Templates;
052: import javax.xml.transform.TransformerConfigurationException;
053: import javax.xml.transform.TransformerException;
054: import javax.xml.transform.TransformerFactory;
055: import javax.xml.transform.stream.StreamResult;
056: import javax.xml.transform.stream.StreamSource;
057:
058: import org.dspace.authorize.AuthorizeException;
059: import org.dspace.content.Bitstream;
060: import org.dspace.content.BitstreamFormat;
061: import org.dspace.content.Bundle;
062: import org.dspace.content.Item;
063: import org.dspace.core.ConfigurationManager;
064: import org.dspace.core.Context;
065: import org.dspace.core.Utils;
066:
067: public class CreativeCommons {
068: /**
069: * The Bundle Name
070: */
071: public static final String CC_BUNDLE_NAME = "CC-LICENSE";
072:
073: private static final String CC_BS_SOURCE = "org.dspace.license.CreativeCommons";
074:
075: /**
076: * Some BitStream Names (BSN)
077: */
078: private static final String BSN_LICENSE_URL = "license_url";
079:
080: private static final String BSN_LICENSE_TEXT = "license_text";
081:
082: private static final String BSN_LICENSE_RDF = "license_rdf";
083:
084: protected static Templates templates = null;
085:
086: private static boolean enabled_p;
087:
088: static {
089: // we only check the property once
090: enabled_p = ConfigurationManager
091: .getBooleanProperty("webui.submit.enable-cc");
092:
093: if (enabled_p) {
094: // if defined, set a proxy server for http requests to Creative
095: // Commons site
096: String proxyHost = ConfigurationManager
097: .getProperty("http.proxy.host");
098: String proxyPort = ConfigurationManager
099: .getProperty("http.proxy.port");
100:
101: if ((proxyHost != null) && (proxyPort != null)) {
102: System.setProperty("http.proxyHost", proxyHost);
103: System.setProperty("http.proxyPort", proxyPort);
104: }
105: }
106:
107: try {
108: templates = TransformerFactory
109: .newInstance()
110: .newTemplates(
111: new StreamSource(
112: CreativeCommons.class
113: .getResourceAsStream("CreativeCommons.xsl")));
114: } catch (TransformerConfigurationException e) {
115: throw new RuntimeException(e.getMessage(), e);
116: }
117:
118: }
119:
120: /**
121: * Simple accessor for enabling of CC
122: */
123: public static boolean isEnabled() {
124: return enabled_p;
125: }
126:
127: // create the CC bundle if it doesn't exist
128: // If it does, remove it and create a new one.
129: private static Bundle getCcBundle(Item item) throws SQLException,
130: AuthorizeException, IOException {
131: Bundle[] bundles = item.getBundles(CC_BUNDLE_NAME);
132:
133: if ((bundles.length > 0) && (bundles[0] != null)) {
134: item.removeBundle(bundles[0]);
135: }
136: return item.createBundle(CC_BUNDLE_NAME);
137: }
138:
139: /**
140: * This is a bit of the "do-the-right-thing" method for CC stuff in an item
141: */
142: public static void setLicense(Context context, Item item,
143: String cc_license_url) throws SQLException, IOException,
144: AuthorizeException {
145: Bundle bundle = getCcBundle(item);
146:
147: // get some more information
148: String license_text = fetchLicenseText(cc_license_url);
149: String license_rdf = fetchLicenseRDF(cc_license_url);
150:
151: // set the format
152: BitstreamFormat bs_format = BitstreamFormat
153: .findByShortDescription(context, "License");
154:
155: // set the URL bitstream
156: setBitstreamFromBytes(item, bundle, BSN_LICENSE_URL, bs_format,
157: cc_license_url.getBytes());
158:
159: // set the license text bitstream
160: setBitstreamFromBytes(item, bundle, BSN_LICENSE_TEXT,
161: bs_format, license_text.getBytes());
162:
163: // set the RDF bitstream
164: setBitstreamFromBytes(item, bundle, BSN_LICENSE_RDF, bs_format,
165: license_rdf.getBytes());
166: }
167:
168: public static void setLicense(Context context, Item item,
169: InputStream licenseStm, String mimeType)
170: throws SQLException, IOException, AuthorizeException {
171: Bundle bundle = getCcBundle(item);
172:
173: // generic "License" format -- change for CC?
174: BitstreamFormat bs_format = BitstreamFormat
175: .findByShortDescription(context, "License");
176:
177: Bitstream bs = bundle.createBitstream(licenseStm);
178: bs.setSource(CC_BS_SOURCE);
179: bs.setName((mimeType != null && (mimeType
180: .equalsIgnoreCase("text/xml") || mimeType
181: .equalsIgnoreCase("text/rdf"))) ? BSN_LICENSE_RDF
182: : BSN_LICENSE_TEXT);
183: bs.setFormat(bs_format);
184: bs.update();
185: }
186:
187: public static void removeLicense(Context context, Item item)
188: throws SQLException, IOException, AuthorizeException {
189: // remove CC license bundle if one exists
190: Bundle[] bundles = item.getBundles(CC_BUNDLE_NAME);
191:
192: if ((bundles.length > 0) && (bundles[0] != null)) {
193: item.removeBundle(bundles[0]);
194: }
195: }
196:
197: public static boolean hasLicense(Context context, Item item)
198: throws SQLException, IOException {
199: // try to find CC license bundle
200: Bundle[] bundles = item.getBundles(CC_BUNDLE_NAME);
201:
202: if (bundles.length == 0) {
203: return false;
204: }
205:
206: // verify it has correct contents
207: try {
208: if ((getLicenseURL(item) == null)
209: || (getLicenseText(item) == null)
210: || (getLicenseRDF(item) == null)) {
211: return false;
212: }
213: } catch (AuthorizeException ae) {
214: return false;
215: }
216:
217: return true;
218: }
219:
220: public static String getLicenseURL(Item item) throws SQLException,
221: IOException, AuthorizeException {
222: return getStringFromBitstream(item, BSN_LICENSE_URL);
223: }
224:
225: public static String getLicenseText(Item item) throws SQLException,
226: IOException, AuthorizeException {
227: return getStringFromBitstream(item, BSN_LICENSE_TEXT);
228: }
229:
230: public static String getLicenseRDF(Item item) throws SQLException,
231: IOException, AuthorizeException {
232: return getStringFromBitstream(item, BSN_LICENSE_RDF);
233: }
234:
235: /**
236: * Get Creative Commons license RDF, returning Bitstream object.
237: * @return bitstream or null.
238: */
239: public static Bitstream getLicenseRdfBitstream(Item item)
240: throws SQLException, IOException, AuthorizeException {
241: return getBitstream(item, BSN_LICENSE_RDF);
242: }
243:
244: /**
245: * Get Creative Commons license Text, returning Bitstream object.
246: * @return bitstream or null.
247: */
248: public static Bitstream getLicenseTextBitstream(Item item)
249: throws SQLException, IOException, AuthorizeException {
250: return getBitstream(item, BSN_LICENSE_TEXT);
251: }
252:
253: /**
254: * Get a few license-specific properties. We expect these to be cached at
255: * least per server run.
256: */
257: public static String fetchLicenseText(String license_url) {
258: String text_url = license_url;
259: byte[] urlBytes = fetchURL(text_url);
260:
261: return (urlBytes != null) ? new String(urlBytes) : "";
262: }
263:
264: public static String fetchLicenseRDF(String license_url) {
265: StringWriter result = new StringWriter();
266:
267: try {
268: templates.newTransformer().transform(
269: new StreamSource(license_url + "rdf"),
270: new StreamResult(result));
271: } catch (TransformerException e) {
272: throw new RuntimeException(e.getMessage(), e);
273: }
274:
275: return result.getBuffer().toString();
276: }
277:
278: // The following two helper methods assume that the CC
279: // bitstreams are short and easily expressed as byte arrays in RAM
280:
281: /**
282: * This helper method takes some bytes and stores them as a bitstream for an
283: * item, under the CC bundle, with the given bitstream name
284: */
285: private static void setBitstreamFromBytes(Item item, Bundle bundle,
286: String bitstream_name, BitstreamFormat format, byte[] bytes)
287: throws SQLException, IOException, AuthorizeException {
288: ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
289: Bitstream bs = bundle.createBitstream(bais);
290:
291: bs.setName(bitstream_name);
292: bs.setSource(CC_BS_SOURCE);
293:
294: bs.setFormat(format);
295:
296: // commit everything
297: bs.update();
298: }
299:
300: /**
301: * This helper method wraps a String around a byte array returned from the
302: * bitstream method further down
303: */
304: private static String getStringFromBitstream(Item item,
305: String bitstream_name) throws SQLException, IOException,
306: AuthorizeException {
307: byte[] bytes = getBytesFromBitstream(item, bitstream_name);
308:
309: if (bytes == null) {
310: return null;
311: }
312:
313: return new String(bytes);
314: }
315:
316: /**
317: * This helper method retrieves the bytes of a bitstream for an item under
318: * the CC bundle, with the given bitstream name
319: */
320: private static Bitstream getBitstream(Item item,
321: String bitstream_name) throws SQLException, IOException,
322: AuthorizeException {
323: Bundle cc_bundle = null;
324:
325: // look for the CC bundle
326: try {
327: Bundle[] bundles = item.getBundles(CC_BUNDLE_NAME);
328:
329: if ((bundles != null) && (bundles.length > 0)) {
330: cc_bundle = bundles[0];
331: } else {
332: return null;
333: }
334: } catch (Exception exc) {
335: // this exception catching is a bit generic,
336: // but basically it happens if there is no CC bundle
337: return null;
338: }
339:
340: return cc_bundle.getBitstreamByName(bitstream_name);
341: }
342:
343: private static byte[] getBytesFromBitstream(Item item,
344: String bitstream_name) throws SQLException, IOException,
345: AuthorizeException {
346: Bitstream bs = getBitstream(item, bitstream_name);
347:
348: // no such bitstream
349: if (bs == null) {
350: return null;
351: }
352:
353: // create a ByteArrayOutputStream
354: ByteArrayOutputStream baos = new ByteArrayOutputStream();
355: Utils.copy(bs.retrieve(), baos);
356:
357: return baos.toByteArray();
358: }
359:
360: /**
361: * Fetch the contents of a URL
362: */
363: private static byte[] fetchURL(String url_string) {
364: try {
365: URL url = new URL(url_string);
366: URLConnection connection = url.openConnection();
367: byte[] bytes = new byte[connection.getContentLength()];
368:
369: // loop and read the data until it's done
370: int offset = 0;
371:
372: while (true) {
373: int len = connection.getInputStream().read(bytes,
374: offset, bytes.length - offset);
375:
376: if (len == -1) {
377: break;
378: }
379:
380: offset += len;
381: }
382:
383: return bytes;
384: } catch (Exception exc) {
385: return null;
386: }
387: }
388: }
|