001 /*
002 * $Revision: 15011 $
003 * $Date: 2009-03-25 11:30:44 +0100 (Wed, 25 Mar 2009) $
004 *
005 * This file is part of *** M y C o R e ***
006 * See http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, in a file called gpl.txt or license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.mycore.datamodel.ifs2;
025
026 import java.io.ByteArrayInputStream;
027 import java.io.ByteArrayOutputStream;
028 import java.io.File;
029 import java.io.FileInputStream;
030 import java.io.FileOutputStream;
031 import java.io.IOException;
032 import java.io.InputStream;
033 import java.io.OutputStream;
034 import java.io.UnsupportedEncodingException;
035 import java.net.URL;
036
037 import org.apache.commons.vfs.FileObject;
038 import org.apache.commons.vfs.FileSystemException;
039 import org.apache.commons.vfs.VFS;
040 import org.jdom.Document;
041 import org.jdom.JDOMException;
042 import org.jdom.input.SAXBuilder;
043 import org.jdom.output.Format;
044 import org.jdom.output.XMLOutputter;
045 import org.mycore.common.MCRUsageException;
046 import org.mycore.common.MCRUtils;
047
048 /**
049 * Used to read/write content from any source to any target. Sources and targets
050 * can be strings, local files, Apache VFS file objects, XML documents, byte[]
051 * arrays and streams. MCRContent can only be consumed once, otherwise the
052 * getters throw MCRUsageException. Use makeCopies() to avoid this. The
053 * underlying input stream is closed after consumption, excepted you use
054 * getInputStream(), of course.
055 *
056 * @author Frank Lützenkirchen
057 */
058 public class MCRContent {
059
060 /**
061 * The content itself
062 */
063 protected InputStream in;
064
065 /**
066 * If true, this content already was used and cannot be used again
067 */
068 protected boolean consumed = false;
069
070 /**
071 * If true, we are absolutely sure that source is XML
072 */
073 protected boolean isXML = false;
074
075 /**
076 * Creates content from a String, using UTF-8 encoding
077 *
078 * @param text
079 * the content
080 */
081 public static MCRContent readFrom(String text) throws IOException, UnsupportedEncodingException {
082 return readFrom(text, "UTF-8");
083 }
084
085 /**
086 * Creates content from a String, using the given encoding
087 *
088 * @param text
089 * the content
090 * @param encoding
091 * the encoding to be used to write bytes
092 */
093 public static MCRContent readFrom(String text, String encoding) throws IOException, UnsupportedEncodingException {
094 return readFrom(text.getBytes(encoding));
095 }
096
097 /**
098 * Creates content from a local file
099 *
100 * @param file
101 * the local file to read
102 */
103 public static MCRContent readFrom(File file) throws IOException {
104 return readFrom(new FileInputStream(file));
105 }
106
107 /**
108 * Creates content from Apache VFS file object
109 *
110 * @param fo
111 * the file object to read content from
112 */
113 public static MCRContent readFrom(FileObject fo) throws FileSystemException {
114 return readFrom(fo.getContent().getInputStream());
115 }
116
117 /**
118 * Creates content from byte[] arrray
119 *
120 * @param bytes
121 * the content's bytes
122 */
123 public static MCRContent readFrom(byte[] bytes) throws IOException {
124 return readFrom(new ByteArrayInputStream(bytes));
125 }
126
127 /**
128 * Creates content from XML document. Content will be written
129 * pretty-formatted, using UTF-8 encoding and line indentation.
130 *
131 * @param xml
132 * the XML document to read in as content
133 */
134 public static MCRContent readFrom(Document xml) throws Exception {
135 ByteArrayOutputStream out = new ByteArrayOutputStream();
136 XMLOutputter xout = new XMLOutputter();
137 xout.setFormat(Format.getPrettyFormat().setEncoding("UTF-8").setIndent(" "));
138 xout.output(xml, out);
139 out.close();
140 MCRContent content = readFrom(out.toByteArray());
141 content.isXML = true;
142 return content;
143 }
144
145 /**
146 * Creates new content from input stream
147 *
148 * @param in
149 * the input stream to read content from
150 */
151 public static MCRContent readFrom(InputStream in) {
152 return new MCRContent(in);
153 }
154
155 private MCRContent(InputStream in) {
156 this.in = in;
157 }
158
159 /**
160 * Creates new content reading from the given URL.
161 *
162 * @param url
163 * the url to read content from
164 */
165 public static MCRContent readFrom(URL url) throws FileSystemException {
166 return readFrom(VFS.getManager().resolveFile(url.toExternalForm()));
167 }
168
169 /**
170 * Ensures that content is XML
171 */
172 public MCRContent ensureXML() throws Exception {
173 if (isXML)
174 return this;
175 else
176 return MCRContent.readFrom(asXML());
177 }
178
179 /**
180 * Returns content as input stream. Be sure to close this stream properly!
181 *
182 * @return input stream to read content from
183 */
184 public InputStream getInputStream() {
185 checkConsumed();
186 return in;
187 }
188
189 /**
190 * Returns content as content input stream, which provides MD5
191 * functionality. Be sure to close this stream properly!
192 *
193 * @return the content input stream
194 */
195 public MCRContentInputStream getContentInputStream() {
196 if (!(in instanceof MCRContentInputStream))
197 in = new MCRContentInputStream(in);
198 return (MCRContentInputStream) in;
199 }
200
201 /**
202 * Sends content to the given OutputStream
203 *
204 * @param out
205 * the OutputStream to write the content to
206 */
207 public void sendTo(OutputStream out) throws IOException {
208 checkConsumed();
209 MCRUtils.copyStream(in, out);
210 in.close();
211 }
212
213 /**
214 * Sends content to the given local file
215 *
216 * @param target
217 * the file to write the content to
218 */
219 public void sendTo(File target) throws IOException {
220 OutputStream out = new FileOutputStream(target);
221 sendTo(out);
222 out.close();
223 }
224
225 /**
226 * Sends the content to the given file object
227 *
228 * @param target
229 * the file to write the content to
230 */
231 public void sendTo(FileObject target) throws IOException, FileSystemException {
232 OutputStream out = target.getContent().getOutputStream();
233 sendTo(out);
234 out.close();
235 }
236
237 /**
238 * Parses content, assuming it is XML, and returns the parsed document.
239 *
240 * @return the XML document parsed from content
241 */
242 public Document asXML() throws JDOMException, IOException {
243 checkConsumed();
244 Document xml = new SAXBuilder().build(in);
245 in.close();
246 return xml;
247 }
248
249 /**
250 * Returns the raw content
251 *
252 * @return the content
253 */
254 public byte[] asByteArray() throws IOException {
255 ByteArrayOutputStream baos = new ByteArrayOutputStream();
256 sendTo(baos);
257 baos.close();
258 return baos.toByteArray();
259 }
260
261 /**
262 * Returns the content as String, assuming the provided encoding
263 *
264 * @param encoding
265 * the encoding to use to build the characters
266 * @return content as String
267 */
268 public String asString(String encoding) throws IOException, UnsupportedEncodingException {
269 return new String(asByteArray(), encoding);
270 }
271
272 /**
273 * Returns content as String, assuming UTF-8 encoding
274 *
275 * @return content as String
276 */
277 public String asString() throws IOException, UnsupportedEncodingException {
278 return asString("UTF-8");
279 }
280
281 /**
282 * Ensures that this content is not already consumed, because it can only be
283 * used once.
284 */
285 protected void checkConsumed() {
286 if (consumed)
287 throw new MCRUsageException("MCRContent is already consumed, can only be used once");
288 else
289 consumed = true;
290 }
291
292 /**
293 * Makes copies of the content, consuming this content
294 *
295 * @param numCopies
296 * the number of copies to make
297 * @return copies of the content
298 */
299 public MCRContent[] makeCopies(int numCopies) throws IOException {
300 MCRContent[] copies = new MCRContent[numCopies];
301 byte[] bytes = asByteArray();
302 for (int i = 0; i < numCopies; i++)
303 copies[i] = MCRContent.readFrom(bytes);
304 return copies;
305 }
306 }