001: /*
002: * argun 1.0
003: * Web 2.0 delivery framework
004: * Copyright (C) 2007 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.web.diagrameditor;
024:
025: import java.io.DataInputStream;
026: import java.io.IOException;
027: import java.io.ObjectInputStream;
028: import java.io.ObjectOutputStream;
029: import java.sql.Connection;
030: import java.sql.PreparedStatement;
031: import java.sql.ResultSet;
032: import java.sql.SQLException;
033: import java.util.HashMap;
034: import java.util.Map;
035: import java.util.zip.GZIPInputStream;
036:
037: import javax.servlet.ServletInputStream;
038: import javax.servlet.ServletOutputStream;
039: import javax.servlet.http.HttpServletRequest;
040: import javax.servlet.http.HttpServletResponse;
041:
042: import org.apache.commons.codec.digest.DigestUtils;
043: import org.apache.commons.lang.StringEscapeUtils;
044: import org.apache.log4j.Logger;
045:
046: import biz.hammurapi.diagram.data.DiagramDocument;
047: import biz.hammurapi.diagram.data.Property;
048: import biz.hammurapi.sql.IdentityGenerator;
049: import biz.hammurapi.sql.IdentityManager;
050: import biz.hammurapi.sql.IdentityRetriever;
051: import biz.hammurapi.sql.Parameterizer;
052: import biz.hammurapi.sql.RowProcessorEx;
053: import biz.hammurapi.sql.SQLExceptionEx;
054: import biz.hammurapi.sql.SQLProcessor;
055: import biz.hammurapi.sql.Transaction;
056: import biz.hammurapi.util.Attributable;
057: import biz.hammurapi.web.ActionServlet;
058: import biz.hammurapi.web.ActionsBase;
059: import biz.hammurapi.web.RequestContext;
060: import biz.hammurapi.web.file.sql.DbFile;
061: import biz.hammurapi.web.file.sql.DbFileImpl;
062: import biz.hammurapi.web.file.sql.FileEngine;
063: import biz.hammurapi.web.util.GuidGenerator;
064:
065: /**
066: * Performs file operations
067: * @author Pavel Vlasov
068: */
069: public class DiagramActions extends ActionsBase {
070: private static final Logger logger = Logger
071: .getLogger(DiagramActions.class);
072:
073: protected static FileEngine getEngine(HttpServletRequest request) {
074: return new FileEngine((SQLProcessor) getGlobal(request,
075: "sql-processor"));
076: }
077:
078: /**
079: * Retrieves content of the file.
080: * @param request
081: * @param response
082: * @throws IOException
083: * @throws SQLException
084: */
085: public void downloadImage(HttpServletRequest request,
086: final HttpServletResponse response, ActionServlet servlet,
087: String path) throws IOException, SQLException {
088: retrieveImage(request, response, true, path);
089: }
090:
091: /**
092: * Retrieves content of the file.
093: * @param request
094: * @param response
095: * @throws IOException
096: * @throws SQLException
097: */
098: public void getImage(HttpServletRequest request,
099: final HttpServletResponse response, ActionServlet servlet,
100: String path) throws IOException, SQLException {
101: retrieveImage(request, response, false, path);
102: }
103:
104: /**
105: * Retrieves content of the file.
106: * @param request
107: * @param response
108: * @throws IOException
109: * @throws SQLException
110: */
111: private void retrieveImage(HttpServletRequest request,
112: final HttpServletResponse response,
113: final boolean setFileName, String path) throws IOException,
114: SQLException {
115: final String fileId;
116: if (isBlank(path)) {
117: fileId = request.getParameter("ID");
118: } else {
119: int idx = path.indexOf("/");
120: if (idx == -1) {
121: response.getWriter().write("Invalid file path");
122: return;
123: }
124: fileId = path.substring(0, idx);
125: }
126:
127: if (fileId == null) {
128: response.getWriter().write("File ID parameter is missing");
129: return;
130: }
131:
132: SQLProcessor processor = (SQLProcessor) getGlobal(request,
133: "sql-processor");
134: processor.processSelect("SELECT * FROM DB_FILE WHERE ID=?",
135: new Parameterizer() {
136:
137: public void parameterize(PreparedStatement ps)
138: throws SQLException {
139: ps.setInt(1, Integer.parseInt(fileId));
140: }
141:
142: }, new RowProcessorEx() {
143:
144: public void onEmptyResultSet() throws SQLException {
145: try {
146: response.getWriter().write(
147: "File " + fileId + " not found");
148: } catch (IOException e) {
149: throw new SQLExceptionEx(e);
150: }
151:
152: }
153:
154: public boolean process(ResultSet rs)
155: throws SQLException {
156: response.setContentType("image/png");
157: if (setFileName) {
158: response.setHeader("Content-Disposition",
159: "attachment; filename=\""
160: + rs.getString("NAME")
161: + "\"");
162: }
163: try {
164: DataInputStream in = new DataInputStream(
165: new GZIPInputStream(
166: rs
167: .getBinaryStream("FILE_CONTENT")));
168: int imageLength = in.readInt();
169: response.setContentLength(imageLength);
170: ServletOutputStream out = response
171: .getOutputStream();
172: byte[] buf = new byte[imageLength];
173: int l;
174: while (imageLength > 0
175: && (l = in.read(buf)) > 0) {
176: out.write(buf, 0, Math.min(l,
177: imageLength));
178: imageLength -= l;
179: }
180: in.close();
181: out.close();
182: } catch (IOException e) {
183: throw new SQLExceptionEx(
184: "Could not retrieve image: " + e, e);
185: }
186: return true;
187: }
188:
189: });
190: }
191:
192: /**
193: * Retrieves diagram for editing
194: * @param request
195: * @param response
196: * @throws IOException
197: * @throws SQLException
198: */
199: public void get(HttpServletRequest request,
200: final HttpServletResponse response) throws IOException,
201: SQLException {
202: final String fileId;
203: fileId = request.getParameter("ID");
204:
205: if (fileId == null) {
206: response.getWriter().write("File ID parameter is missing");
207: return;
208: }
209:
210: DbFile ret = getEngine(request).getDbFile(
211: Integer.parseInt(fileId));
212: ObjectOutputStream oos = new ObjectOutputStream(response
213: .getOutputStream());
214: oos.writeObject(ret);
215: oos.close();
216: }
217:
218: private Map createMap = new HashMap();
219:
220: /**
221: * Stores diagram in the database.
222: * @param request
223: * @param response
224: */
225: public void save(final HttpServletRequest request,
226: HttpServletResponse response) throws IOException {
227: try {
228: ServletInputStream in = request.getInputStream();
229: ObjectInputStream ois = new ObjectInputStream(in);
230: DbFile data = (DbFile) ois.readObject();
231: ois.close();
232: boolean isNew = data instanceof Attributable
233: && Boolean.TRUE.equals(((Attributable) data)
234: .getAttribute(DiagramEditorApplet.IS_NEW));
235: FileEngine engine = getEngine(request);
236: final DbFile dataToStore = isNew ? new DbFileImpl(true)
237: : engine.getDbFile(data.getId());
238: dataToStore.setContentType(data.getContentType());
239: dataToStore.setDescription(StringEscapeUtils
240: .escapeHtml(data.getDescription()));
241: dataToStore.setFileContent(data.getFileContent());
242: dataToStore.setFileSize(new Long(
243: data.getFileContent().length));
244: if (!isNew) {
245: dataToStore.setId(data.getId());
246: }
247: dataToStore.setLastModified(System.currentTimeMillis());
248: dataToStore.setName(StringEscapeUtils.escapeHtml(data
249: .getName()));
250: dataToStore.setOwnerId(data.getOwnerId());
251: dataToStore.setOwnerType(data.getOwnerType());
252: dataToStore.setParent(data.getParent());
253:
254: dataToStore.setDigest(DigestUtils.shaHex(data
255: .getFileContent()));
256: dataToStore.setDigestAlgorithm("SHA");
257:
258: dataToStore.setGuid(data.getGuid());
259: GuidGenerator guidGenerator = (GuidGenerator) getGlobal(
260: request, "db/guid-generator");
261: if (guidGenerator != null && isBlank(dataToStore.getGuid())) {
262: dataToStore.setGuid(guidGenerator.nextGUID());
263: }
264:
265: final Object createId = data instanceof Attributable ? ((Attributable) data)
266: .getAttribute(DiagramEditorApplet.CREATE_ID)
267: : null;
268: if (isNew && createId != null) {
269: synchronized (createMap) {
270: Integer id = (Integer) createMap.get(createId);
271: if (id != null) {
272: dataToStore.setId(id.intValue());
273: isNew = false;
274: }
275: }
276: }
277:
278: onSave(dataToStore);
279:
280: if (isNew) {
281:
282: Transaction createTransaction = new Transaction() {
283:
284: public boolean execute(SQLProcessor processor)
285: throws SQLException {
286: IdentityManager identityManager = (IdentityManager) getGlobal(
287: request, "db/IdentityManager");
288: Connection con = processor.getConnection();
289: FileEngine engine = new FileEngine(
290: new SQLProcessor(con, null));
291: if (identityManager instanceof IdentityGenerator) {
292: dataToStore
293: .setId(((IdentityGenerator) identityManager)
294: .generate(con, "DB_FILE"));
295: }
296:
297: engine.insertDbFile(dataToStore);
298: if (identityManager instanceof IdentityRetriever) {
299: dataToStore
300: .setId(((IdentityRetriever) identityManager)
301: .retrieve(con));
302: }
303:
304: processor.releaseConnection(con);
305:
306: if (createId != null) {
307: synchronized (createMap) {
308: createMap.put(createId, new Integer(
309: dataToStore.getId()));
310: }
311: }
312: return true;
313: }
314:
315: };
316:
317: SQLProcessor processor = (SQLProcessor) getGlobal(
318: request, "sql-processor");
319: processor.executeTransaction(createTransaction);
320: } else {
321: if (engine.updateDbFile(dataToStore) != 1) {
322: logger.error("Storing diagram to DB failed");
323: response.sendError(500,
324: "Storing diagram to DB failed");
325: }
326: }
327: } catch (Exception e) {
328: logger.error("Could not create/update diagram", e);
329: response.sendError(500, e.toString());
330: }
331: }
332:
333: /**
334: * Subclasses can override this method to implement additional actions on/with file content
335: * @param dataToStore
336: */
337: protected void onSave(DbFile dataToStore) {
338:
339: }
340:
341: /**
342: * Retrieves content of the file.
343: * @param request
344: * @param response
345: * @throws IOException
346: * @throws SQLException
347: */
348: public Object getContent(final HttpServletRequest request,
349: final HttpServletResponse response) throws SQLException {
350: final String fileId = request.getParameter("ID");
351:
352: if (fileId == null) {
353: return "File ID parameter is missing";
354: }
355:
356: final Object[] ret = { null };
357:
358: SQLProcessor processor = (SQLProcessor) getGlobal(request,
359: "sql-processor");
360: processor.processSelect("SELECT * FROM DB_FILE WHERE ID=?",
361: new Parameterizer() {
362:
363: public void parameterize(PreparedStatement ps)
364: throws SQLException {
365: ps.setInt(1, Integer.parseInt(fileId));
366: }
367:
368: }, new RowProcessorEx() {
369:
370: public void onEmptyResultSet() throws SQLException {
371: try {
372: response.getWriter().write(
373: "File " + fileId + " not found");
374: } catch (IOException e) {
375: throw new SQLExceptionEx(e);
376: }
377:
378: }
379:
380: public boolean process(ResultSet rs)
381: throws SQLException {
382: response.setContentType("text/xml");
383: try {
384: DataInputStream in = new DataInputStream(
385: new GZIPInputStream(
386: rs
387: .getBinaryStream("FILE_CONTENT")));
388: int offset = in.readInt();
389: in.skip(offset);
390: final DiagramDocument diagramDocument = DiagramDocument.Factory
391: .parse(in);
392: in.close();
393: Property property = diagramDocument
394: .getDiagram().addNewProperty();
395: property.setName("file-id");
396: property.setStringValue(rs.getString("ID"));
397: property = diagramDocument.getDiagram()
398: .addNewProperty();
399: property.setName("context-path");
400: property
401: .setStringValue((String) new RequestContext(
402: request)
403: .get("context-path"));
404: ret[0] = diagramDocument.getDomNode();
405: } catch (Exception e) {
406: throw new SQLExceptionEx(
407: "Could not retrieve file content: "
408: + e, e);
409: }
410: return true;
411: }
412:
413: });
414:
415: return ret[0];
416: }
417:
418: }
|