0001: /***************************************************************
0002: * This file is part of the [fleXive](R) project.
0003: *
0004: * Copyright (c) 1999-2008
0005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
0006: * All rights reserved
0007: *
0008: * The [fleXive](R) project is free software; you can redistribute
0009: * it and/or modify it under the terms of the GNU General Public
0010: * License as published by the Free Software Foundation;
0011: * either version 2 of the License, or (at your option) any
0012: * later version.
0013: *
0014: * The GNU General Public License can be found at
0015: * http://www.gnu.org/copyleft/gpl.html.
0016: * A copy is found in the textfile GPL.txt and important notices to the
0017: * license from the author are found in LICENSE.txt distributed with
0018: * these libraries.
0019: *
0020: * This library is distributed in the hope that it will be useful,
0021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0023: * GNU General Public License for more details.
0024: *
0025: * For further information about UCS - unique computing solutions gmbh,
0026: * please see the company website: http://www.ucs.at
0027: *
0028: * For further information about [fleXive](R), please see the
0029: * project website: http://www.flexive.org
0030: *
0031: *
0032: * This copyright notice MUST APPEAR in all copies of the file!
0033: ***************************************************************/package com.flexive.ejb.beans;
0034:
0035: import com.flexive.core.Database;
0036: import static com.flexive.core.DatabaseConst.*;
0037: import com.flexive.core.storage.StorageManager;
0038: import com.flexive.shared.CacheAdmin;
0039: import com.flexive.shared.FxContext;
0040: import com.flexive.shared.exceptions.FxApplicationException;
0041: import com.flexive.shared.exceptions.FxLoadException;
0042: import com.flexive.shared.exceptions.FxNotFoundException;
0043: import com.flexive.shared.exceptions.FxUpdateException;
0044: import com.flexive.shared.interfaces.SequencerEngine;
0045: import com.flexive.shared.interfaces.TemplateEngine;
0046: import com.flexive.shared.interfaces.TemplateEngineLocal;
0047: import com.flexive.shared.security.UserTicket;
0048: import com.flexive.shared.tree.FxTemplateInfo;
0049: import com.flexive.shared.tree.FxTemplateMapping;
0050: import com.flexive.shared.tree.FxTreeMode;
0051: import static com.flexive.shared.tree.FxTreeMode.Edit;
0052: import static com.flexive.shared.tree.FxTreeMode.Live;
0053: import com.flexive.shared.tree.FxTreeNode;
0054: import org.apache.commons.logging.Log;
0055: import org.apache.commons.logging.LogFactory;
0056:
0057: import javax.annotation.Resource;
0058: import javax.ejb.*;
0059: import java.sql.*;
0060: import java.util.ArrayList;
0061: import java.util.Hashtable;
0062: import java.util.List;
0063: import java.util.regex.Matcher;
0064: import java.util.regex.Pattern;
0065:
0066: @Stateless(name="TemplateEngine")
0067: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0068: @TransactionManagement(TransactionManagementType.CONTAINER)
0069: public class TemplateEngineBean implements TemplateEngine,
0070: TemplateEngineLocal {
0071:
0072: private static transient Log LOG = LogFactory
0073: .getLog(TemplateEngineBean.class);
0074: @Resource
0075: javax.ejb.SessionContext ctx;
0076: @EJB
0077: private SequencerEngine seq;
0078:
0079: private void registerChange(Type type, FxTreeMode mode) {
0080: try {
0081: CacheAdmin.getInstance().put(
0082: this .getClass().getName() + ".lastChange",
0083: mode + "_" + type.toString(),
0084: java.lang.System.currentTimeMillis());
0085: CacheAdmin.getInstance().put(
0086: this .getClass().getName() + ".lastChange",
0087: mode + "_" + "global",
0088: java.lang.System.currentTimeMillis());
0089: } catch (Throwable t) {
0090: LOG.error(t);
0091: }
0092: }
0093:
0094: /**
0095: * {@inheritDoc} *
0096: */
0097: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0098: public long getLastChange(Type type, FxTreeMode mode) { // TODO
0099: String key = mode + "_" + type == null ? "global" : type
0100: .toString();
0101: try {
0102: Long lastChange = (Long) CacheAdmin.getInstance().get(
0103: this .getClass().getName() + ".lastChange", key);
0104: if (lastChange == null) {
0105: registerChange(type, mode);
0106: lastChange = (Long) CacheAdmin.getInstance().get(
0107: this .getClass().getName() + ".lastChange", key);
0108: }
0109: return lastChange;
0110: } catch (Throwable t) {
0111: LOG.error(t);
0112: return java.lang.System.currentTimeMillis();
0113: }
0114: }
0115:
0116: /**
0117: * {@inheritDoc} *
0118: */
0119: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0120: public long create(String name, Type type, String contentType,
0121: String content) throws FxApplicationException {
0122:
0123: Connection con = null;
0124: PreparedStatement ps = null;
0125: long newId = -1;
0126: int typeid = 0;
0127: try {
0128: newId = seq.getId(SequencerEngine.System.TEMPLATE);
0129: // Determine the next type id to use, fill holes!
0130: con = Database.getDbConnection();
0131: ps = con.prepareStatement("SELECT TYPEID from "
0132: + TBL_TEMPLATE + " where TEMPLATE_TYPE='"
0133: + type.getDbValue() + "'");
0134: ResultSet rs = ps.executeQuery();
0135: while (rs != null && rs.next()) {
0136: if (rs.getInt(1) > typeid) {
0137: break;
0138: }
0139: typeid++;
0140: }
0141: ps.close();
0142: } catch (FxApplicationException t) {
0143: throw t;
0144: } catch (Throwable t) {
0145: ctx.setRollbackOnly();
0146: FxUpdateException exc = new FxUpdateException(t,
0147: "Template.err.create.failed", name);
0148: LOG.error(exc);
0149: throw exc;
0150: } finally {
0151: Database.closeObjects(TreeEngineBean.class, con, ps);
0152: }
0153:
0154: _create(newId, typeid, Edit, name, type, contentType, content,
0155: false);
0156: return newId;
0157: }
0158:
0159: /**
0160: * @param id
0161: * @param typeid
0162: * @param mode
0163: * @param name
0164: * @param type
0165: * @param contentType
0166: * @param content
0167: * @param inSync
0168: * @throws FxApplicationException
0169: */
0170: private void _create(long id, int typeid, FxTreeMode mode,
0171: String name, Type type, String contentType, String content,
0172: boolean inSync) throws FxApplicationException {
0173: Connection con = null;
0174: PreparedStatement ps = null;
0175: try {
0176: // Do sanity checks
0177: checkTagName(type, name);
0178: FxTemplateInfo master = getMasterTemplate(type, content,
0179: mode);
0180: StringBuffer finalContent = new StringBuffer(content);
0181: ArrayList<FxTemplateInfo> tags = getTags(finalContent, mode);
0182: UserTicket ticket = FxContext.get().getTicket();
0183:
0184: // Create the entry
0185: con = Database.getDbConnection();
0186: ps = con
0187: .prepareStatement("INSERT INTO "
0188: + TBL_TEMPLATE
0189: +
0190: // 1, 2 , 3 , 4 , 5 , 6 , 7 , 8
0191: // 9 ,10
0192: "(ID,TYPEID,NAME,CONTENT_TYPE,CONTENT,CREATED_BY ,CREATED_AT,MODIFIED_BY,MODIFIED_AT,"
0193: + "TEMPLATE_TYPE,MASTER_TEMPLATE,FINAL_CONTENT,ISLIVE,INSYNC) "
0194: + "values (?,?,?,?,?,?,?,?,?,?,?,?,"
0195: + (mode == Live) + "," + inSync + ")");
0196: final long NOW = System.currentTimeMillis();
0197: ps.setLong(1, id);
0198: ps.setInt(2, typeid);
0199: ps.setString(3, name);
0200: ps.setString(4, contentType);
0201: ps.setString(5, content);
0202: ps.setLong(6, ticket.getUserId());
0203: ps.setLong(7, NOW);
0204: ps.setLong(8, ticket.getUserId());
0205: ps.setLong(9, NOW);
0206: ps.setString(10, String.valueOf(type.getDbValue()));
0207: if (master == null) {
0208: ps.setNull(11, java.sql.Types.INTEGER);
0209: } else {
0210: ps.setLong(11, master.getId());
0211: }
0212: ps.setString(12, finalContent.toString());
0213: ps.executeUpdate();
0214: ps.close();
0215:
0216: // Update inSync in Edit AND Live version (if available)
0217: ps = con.prepareStatement("UPDATE " + TBL_TEMPLATE
0218: + " SET INSYNC=" + inSync + " WHERE ID=" + id);
0219: ps.executeUpdate();
0220:
0221: registerTagRelations(con, id, mode, tags);
0222: registerChange(type, mode);
0223: } catch (FxApplicationException t) {
0224: throw t;
0225: } catch (Throwable t) {
0226: ctx.setRollbackOnly();
0227: FxUpdateException exc = new FxUpdateException(t,
0228: "Template.err.create.failed", name);
0229: LOG.error(exc);
0230: throw exc;
0231: } finally {
0232: Database.closeObjects(TreeEngineBean.class, con, ps);
0233: }
0234: }
0235:
0236: /**
0237: * Activates the template with the given id.
0238: *
0239: * @param id the id of the template
0240: * @throws FxApplicationException if the function fails
0241: */
0242: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0243: public void activate(long id) throws FxApplicationException {
0244: // Check if the template exists at all
0245: FxTemplateInfo self = getInfo(id, Edit);
0246: if (self == null) {
0247: throw new FxNotFoundException("Template.err.notFound", id);
0248: }
0249: // Activate the template
0250: Connection con = null;
0251: Statement stmt = null;
0252: try {
0253:
0254: // Delete any old LIVE version
0255: con = Database.getDbConnection();
0256: stmt = con.createStatement();
0257: stmt.executeUpdate("DELETE FROM " + TBL_TEMPLATE
0258: + " WHERE ID=" + id + " AND ISLIVE=true");
0259:
0260: // Try to create the new LIVE version
0261: FxTemplateInfo info = getInfo(id, Edit);
0262: String content = getContent(id, Edit);
0263: _create(id, (int) info.getTypeId(), Live, info.getName(),
0264: info.getTemplateType(), info.getContentType(),
0265: content, true);
0266:
0267: } catch (Throwable t) {
0268: ctx.setRollbackOnly();
0269: FxUpdateException exc = new FxUpdateException(t,
0270: "Template.err.activate.failed", id);
0271: LOG.error(exc);
0272: throw exc;
0273: } finally {
0274: Database.closeObjects(TreeEngineBean.class, con, stmt);
0275: }
0276: }
0277:
0278: /**
0279: * {@inheritDoc} *
0280: */
0281: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0282: public void setContent(long id, String content, String type,
0283: FxTreeMode mode) throws FxApplicationException {
0284: Connection con = null;
0285: PreparedStatement ps = null;
0286: try {
0287: FxTemplateInfo self = getInfo(id, mode);
0288: FxTemplateInfo master = getMasterTemplate(self
0289: .getTemplateType(), content, mode);
0290: StringBuffer finalContent = new StringBuffer(content);
0291: ArrayList<FxTemplateInfo> tags = getTags(finalContent, mode);
0292: UserTicket ticket = FxContext.get().getTicket();
0293: con = Database.getDbConnection();
0294: ps = con
0295: .prepareStatement("UPDATE "
0296: + TBL_TEMPLATE
0297: + " set CONTENT_TYPE=?, CONTENT=?, "
0298: + " MODIFIED_AT=?,MODIFIED_BY=?,MASTER_TEMPLATE=?,FINAL_CONTENT=? "
0299: + " where id=" + id + " and islive="
0300: + (mode == Live));
0301: ps.setString(1, type);
0302: ps.setString(2, content);
0303: ps.setLong(3, System.currentTimeMillis());
0304: ps.setLong(4, ticket.getUserId());
0305: if (master == null) {
0306: ps.setNull(5, java.sql.Types.INTEGER);
0307: } else {
0308: ps.setLong(5, master.getId());
0309: }
0310: ps.setString(6, finalContent.toString());
0311: ps.executeUpdate();
0312: ps.close();
0313:
0314: // Check if the live and edit versions are in sync (=equal)
0315: ps = con.prepareStatement("select\n"
0316: + "((select content from " + TBL_TEMPLATE
0317: + " where id=" + id + " and islive=false)=\n"
0318: + "(select content from " + TBL_TEMPLATE
0319: + " where id=" + id + " and islive=true))");
0320: ResultSet rs = ps.executeQuery();
0321: rs.next();
0322: boolean inSync = rs.getBoolean(1);
0323: ps.close();
0324:
0325: // Update the inSync flag of both versions
0326: ps = con.prepareStatement("UPDATE " + TBL_TEMPLATE
0327: + " set INSYNC=" + inSync + " where id=" + id);
0328: ps.executeUpdate();
0329: ps.close();
0330: ps = null;
0331:
0332: // Update relations and the last change date
0333: registerTagRelations(con, id, mode, tags);
0334: registerChange(self.getTemplateType(), mode);
0335: } catch (FxApplicationException e) {
0336: throw e;
0337: } catch (Throwable t) {
0338: ctx.setRollbackOnly();
0339: FxUpdateException exc = new FxUpdateException(t,
0340: "Template.err.setContent.failed", id);
0341: LOG.error(exc);
0342: throw exc;
0343: } finally {
0344: Database.closeObjects(TreeEngineBean.class, con, ps);
0345: }
0346: }
0347:
0348: /**
0349: * Stores the tag relations in the database.
0350: *
0351: * @param con the connection to use
0352: * @param id the id of the template
0353: * @param tags the tags the template is using
0354: * @param mode tree mode
0355: * @throws FxUpdateException if a error occurs
0356: */
0357: private void registerTagRelations(Connection con, long id,
0358: FxTreeMode mode, ArrayList<FxTemplateInfo> tags)
0359: throws FxUpdateException {
0360: Statement stmt = null;
0361: try {
0362: stmt = con.createStatement();
0363: stmt.executeUpdate("DELETE FROM " + TBL_TAG_RELATIONS
0364: + " where TEMPLATE_ID=" + id
0365: + " and TEMPLATE_ISLIVE=" + (mode == Live));
0366: stmt.close();
0367:
0368: for (FxTemplateInfo tag : tags) {
0369: stmt = con.createStatement();
0370: stmt.executeUpdate("INSERT INTO " + TBL_TAG_RELATIONS
0371: + " (TEMPLATE_ID,TAG_ID,TEMPLATE_ISLIVE) "
0372: + " value (" + id + "," + tag.getId() + ","
0373: + (mode == Live) + ")");
0374: stmt.close();
0375: }
0376: } catch (Throwable t) {
0377: ctx.setRollbackOnly();
0378: FxUpdateException exc = new FxUpdateException(t,
0379: "Template.err.setTagRelations.failed", id, t
0380: .getMessage());
0381: LOG.error(exc);
0382: throw exc;
0383: } finally {
0384: Database.closeObjects(TreeEngineBean.class, null, stmt);
0385: }
0386: }
0387:
0388: /**
0389: * {@inheritDoc} *
0390: */
0391: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0392: public boolean templateIsReferenced(long id) throws FxLoadException {
0393: Connection con = null;
0394: Statement stmt = null;
0395: try {
0396: con = Database.getDbConnection();
0397: stmt = con.createStatement();
0398: ResultSet rs = stmt.executeQuery("select\n"
0399: + "(select count(*) from " + TBL_TAG_RELATIONS
0400: + " where tag_id=" + id + ") +\n"
0401: + "(select count(*) from " + TBL_TEMPLATE
0402: + " where MASTER_TEMPLATE=" + id + ")");
0403: rs.next();
0404: long count = rs.getLong(1);
0405: return count > 0;
0406: } catch (Throwable t) {
0407: ctx.setRollbackOnly();
0408: FxLoadException exc = new FxLoadException(t,
0409: "Template.err.templateIsReferenced.failed", id, t
0410: .getMessage());
0411: LOG.error(exc);
0412: throw exc;
0413: } finally {
0414: Database.closeObjects(TreeEngineBean.class, con, stmt);
0415: }
0416:
0417: }
0418:
0419: /**
0420: * Returns a list of all tags used in the template, and modifies the content to the
0421: * final_content.
0422: *
0423: * @param content the content
0424: * @param mode tree mode
0425: * @return the tag list and a modified content
0426: * @throws FxApplicationException if the function fails
0427: */
0428: private ArrayList<FxTemplateInfo> getTags(
0429: final StringBuffer content, FxTreeMode mode)
0430: throws FxApplicationException {
0431: // Compile the regex.
0432: Pattern pattern = Pattern.compile("<cms:([^\\>])+>");
0433:
0434: // A list of all used tags
0435: ArrayList<FxTemplateInfo> tags = new ArrayList<FxTemplateInfo>(
0436: 25);
0437: Hashtable<String, Boolean> dups = new Hashtable<String, Boolean>(
0438: 25);
0439: Hashtable<String, FxTemplateInfo> replace = new Hashtable<String, FxTemplateInfo>(
0440: 25);
0441:
0442: // Get a Matcher based on the content string
0443: Matcher matcher = pattern.matcher(content);
0444:
0445: // Find all the matches.
0446: while (matcher.find()) {
0447: String tagName = matcher.group().split(" ")[0].substring(5);
0448: Object exists = dups.put(tagName, Boolean.TRUE);
0449: try {
0450: FxTemplateInfo nfo = getInfo(tagName, mode);
0451: if (nfo == null)
0452: throw new Exception("notFoundDummy");
0453: if (exists == null) {
0454: tags.add(nfo);
0455: }
0456: replace.put(matcher.group(), nfo);
0457: } catch (Throwable t) {
0458: FxUpdateException exc = new FxUpdateException(t,
0459: "Template.err.invalidTag", tagName);
0460: LOG.debug(exc);
0461: throw exc;
0462: }
0463: }
0464:
0465: // Replace the user-tags with the internal tags
0466: String result = content.toString();
0467: for (String userTag : replace.keySet()) {
0468: while (result.indexOf(userTag) != -1) {
0469: String suffix = userTag.substring(replace.get(userTag)
0470: .getName().length() + 5);
0471: String prefix = "<cms:tag"
0472: + replace.get(userTag).getTypeId() + " ";
0473: result = replace(result, userTag, prefix + suffix);
0474: }
0475: }
0476: content.delete(0, content.length());
0477: content.append(result);
0478:
0479: return tags;
0480: }
0481:
0482: public static String replace(final String aInput,
0483: final String aOldPattern, final String aNewPattern) {
0484: if (aOldPattern.equals("")) {
0485: throw new IllegalArgumentException(
0486: "Old pattern must have content.");
0487: }
0488:
0489: final StringBuffer result = new StringBuffer();
0490: //startIdx and idxOld delimit various chunks of aInput; these
0491: //chunks always end where aOldPattern begins
0492: int startIdx = 0;
0493: int idxOld;
0494: while ((idxOld = aInput.indexOf(aOldPattern, startIdx)) >= 0) {
0495: //grab a part of aInput which does not include aOldPattern
0496: result.append(aInput.substring(startIdx, idxOld));
0497: //add aNewPattern to take place of aOldPattern
0498: result.append(aNewPattern);
0499:
0500: //reset the startIdx to just after the current match, to see
0501: //if there are any further matches
0502: startIdx = idxOld + aOldPattern.length();
0503: }
0504: //the final chunk will go to the end of aInput
0505: result.append(aInput.substring(startIdx));
0506: return result.toString();
0507: }
0508:
0509: /**
0510: * Returns the master template used by the content, or null if none is set.
0511: *
0512: * @param type the template type
0513: * @param content the content
0514: * @param mode tree mode
0515: * @return the name of the master template
0516: * @throws FxApplicationException when the referenced master template is invalid
0517: */
0518: private FxTemplateInfo getMasterTemplate(final Type type,
0519: final String content, FxTreeMode mode)
0520: throws FxApplicationException {
0521: FxTemplateInfo master = null;
0522: String sMaster = null;
0523: if (type == Type.CONTENT)
0524: try {
0525: // Extract the name of the master template
0526: sMaster = content
0527: .split("<ui:composition[\\s]*template[\\s]*=[\\s]*\"")[1]
0528: .split("\"[\\s]*>")[0];
0529: } catch (Throwable t) {
0530: /* its okay */
0531: }
0532: if (sMaster != null)
0533: try {
0534: // Check if the template exists
0535: master = getInfo(sMaster, mode);
0536: // Throw null pointer if the mast is not defined
0537: master.getName();
0538: } catch (Throwable t) {
0539: FxUpdateException exc = new FxUpdateException(t,
0540: "Template.err.invalidMasterTemplate", sMaster);
0541: LOG.debug(exc);
0542: throw exc;
0543: }
0544: return master;
0545: }
0546:
0547: /**
0548: * {@inheritDoc} *
0549: */
0550: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0551: public void setName(long id, String name)
0552: throws FxApplicationException {
0553: Connection con = null;
0554: PreparedStatement ps = null;
0555: try {
0556: FxTemplateInfo nfo = getInfo(id, Edit); // TODO: Refs! Live Mode!!!
0557: checkTagName(nfo.getTemplateType(), name);
0558: UserTicket ticket = FxContext.get().getTicket();
0559: con = Database.getDbConnection();
0560: ps = con.prepareStatement("UPDATE " + TBL_TEMPLATE
0561: + " set NAME=?,MODIFIED_AT=?,"
0562: + "MODIFIED_BY=? where id=" + id);
0563: ps.setString(1, name);
0564: ps.setLong(2, System.currentTimeMillis());
0565: ps.setLong(3, ticket.getUserId());
0566: ps.executeUpdate();
0567: registerChange(nfo.getTemplateType(), Live);
0568: registerChange(nfo.getTemplateType(), Edit);
0569: } catch (FxApplicationException t) {
0570: throw t;
0571: } catch (Throwable t) {
0572: ctx.setRollbackOnly();
0573: FxUpdateException exc = new FxUpdateException(t,
0574: "Template.err.setName.failed", id);
0575: LOG.error(exc);
0576: throw exc;
0577: } finally {
0578: Database.closeObjects(TreeEngineBean.class, con, ps);
0579: }
0580: }
0581:
0582: private void checkTagName(Type type, String name)
0583: throws FxUpdateException {
0584: if (type == Type.TAG) {
0585: if (name.split("\\s").length > 1) {
0586: throw new FxUpdateException(
0587: "Template.err.invalidTagNameNoWhitespace");
0588: }
0589: }
0590: }
0591:
0592: /**
0593: * {@inheritDoc} *
0594: */
0595: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0596: public FxTemplateInfo getInfo(long id, FxTreeMode mode)
0597: throws FxApplicationException {
0598: return _getInfo(id, null, mode);
0599: }
0600:
0601: /**
0602: * {@inheritDoc} *
0603: */
0604: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0605: public FxTemplateInfo getInfo(String name, FxTreeMode mode)
0606: throws FxApplicationException {
0607: return _getInfo(null, name, mode);
0608: }
0609:
0610: private FxTemplateInfo _getInfo(Long id, String name,
0611: FxTreeMode mode) throws FxApplicationException {
0612: Connection con = null;
0613: PreparedStatement ps = null;
0614: try {
0615: con = Database.getDbConnection();
0616:
0617: String condition = " ";
0618: if (id != null)
0619: condition += "id=" + id;
0620: if (id != null && name != null)
0621: condition += " and ";
0622: if (name != null)
0623: condition += "name=?";
0624:
0625: String sSql = "SELECT ID,TYPEID,CONTENT_TYPE,MODIFIED_BY,MODIFIED_AT,NAME,TEMPLATE_TYPE,MASTER_TEMPLATE,\n"
0626: +
0627: // Last modification Timestamp
0628: "IF(master_template is null,null,(select sub.modified_at from "
0629: + TBL_TEMPLATE
0630: + " sub where sub.id=t.master_template)),\n"
0631: +
0632: // Does this template have an LIVE version?
0633: "(select 1 from "
0634: + TBL_TEMPLATE
0635: + " where "
0636: + condition
0637: + " and islive=true),\n"
0638: + "INSYNC \n"
0639: + " FROM "
0640: + TBL_TEMPLATE
0641: + " t where islive="
0642: + (mode == Live) + " and " + condition;
0643:
0644: ps = con.prepareStatement(sSql);
0645: if (name != null) {
0646: ps.setString(1, name);
0647: ps.setString(2, name);
0648: }
0649: ResultSet rs = ps.executeQuery();
0650:
0651: if (rs.next()) {
0652: long _id = rs.getLong(1);
0653: int _typeid = rs.getInt(2);
0654: String _type = rs.getString(3);
0655: long _modifiedBy = rs.getLong(4);
0656: long _modifiedAt = rs.getLong(5);
0657: String _name = rs.getString(6);
0658: Type _ttype = Type.fromString(rs.getString(7));
0659: Long _master = rs.getLong(8);
0660: if (rs.wasNull()) {
0661: _master = null;
0662: }
0663: final long tstp = rs.getLong(9);
0664: long _masterMod = -1;
0665: if (!rs.wasNull())
0666: _masterMod = tstp;
0667: boolean hasLive = rs.getLong(10) == 1;
0668: boolean inSync = rs.getBoolean(11);
0669:
0670: return new FxTemplateInfo(_id, _typeid, _name, _type,
0671: _modifiedAt, _modifiedBy, -1, _ttype, _master,
0672: _masterMod, mode == Live, hasLive, inSync);
0673: } else {
0674: return null;
0675: }
0676: } catch (Throwable t) {
0677: FxUpdateException exc = new FxUpdateException(t,
0678: "Template.err.load.failed", id);
0679: LOG.error(exc);
0680: throw exc;
0681: } finally {
0682: Database.closeObjects(TreeEngineBean.class, con, ps);
0683: }
0684: }
0685:
0686: /**
0687: * {@inheritDoc} *
0688: */
0689: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0690: public ArrayList<FxTemplateInfo> list(Type type)
0691: throws FxApplicationException {
0692: Connection con = null;
0693: Statement stmt = null;
0694: ArrayList<FxTemplateInfo> result = new ArrayList<FxTemplateInfo>(
0695: 250);
0696: try {
0697: con = Database.getDbConnection();
0698: stmt = con.createStatement();
0699: String sSql = "SELECT id,typeid,CONTENT_TYPE,MODIFIED_BY,MODIFIED_AT,NAME,TEMPLATE_TYPE,MASTER_TEMPLATE,\n"
0700: + "IF(master_template is null,-1,(select sub.modified_at from "
0701: + TBL_TEMPLATE
0702: + " sub where sub.id=t.master_template)),\n"
0703: + "(select 1 from "
0704: + TBL_TEMPLATE
0705: + " sub where sub.id=t.id and islive=true),\n "
0706: + "INSYNC\n" + " FROM " + TBL_TEMPLATE + " t ";
0707: if (type != null) {
0708: sSql += " where template_type='" + type.toString()
0709: + "' and islive=false";
0710: }
0711: ResultSet rs = stmt.executeQuery(sSql);
0712: while (rs.next()) {
0713: long id = rs.getLong(1);
0714: int typeid = rs.getInt(2);
0715: String contentType = rs.getString(3);
0716: long modifiedBy = rs.getLong(4);
0717: long modifiedAt = rs.getLong(5);
0718: String name = rs.getString(6);
0719: Type _ttype = Type.fromString(rs.getString(7));
0720: Long _master = rs.getLong(8);
0721: if (rs.wasNull()) {
0722: _master = null;
0723: }
0724: final long tstp = rs.getLong(9);
0725: long _masterMod = -1;
0726: if (!rs.wasNull())
0727: _masterMod = tstp;
0728: boolean hasLive = rs.getInt(10) == 1;
0729: boolean inSync = rs.getBoolean(11);
0730: result.add(new FxTemplateInfo(id, typeid, name,
0731: contentType, modifiedAt, modifiedBy, -1,
0732: _ttype, _master, _masterMod, false, hasLive,
0733: inSync));
0734: }
0735: return result;
0736: } catch (Throwable t) {
0737: FxUpdateException exc = new FxUpdateException(t,
0738: "Template.err.list.failed");
0739: LOG.error(exc);
0740: throw exc;
0741: } finally {
0742: Database.closeObjects(TreeEngineBean.class, con, stmt);
0743: }
0744: }
0745:
0746: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0747: private String _getContent(long id, boolean getFinal,
0748: FxTreeMode mode) throws FxApplicationException {
0749: Connection con = null;
0750: Statement stmt = null;
0751: try {
0752: con = Database.getDbConnection();
0753: stmt = con.createStatement();
0754: String selectCol = getFinal ? "ifnull(FINAL_CONTENT,content)"
0755: : "content";
0756: ResultSet rs = stmt.executeQuery("SELECT " + selectCol
0757: + " FROM " + TBL_TEMPLATE + " where id=" + id
0758: + " and islive=" + (mode == Live));
0759: if (rs.next()) {
0760: return rs.getString(1);
0761: } else {
0762: return null;
0763: }
0764: } catch (Throwable t) {
0765: FxUpdateException exc = new FxUpdateException(t,
0766: "Template.err.loadContent.failed", id);
0767: LOG.error(exc);
0768: throw exc;
0769: } finally {
0770: Database.closeObjects(TreeEngineBean.class, con, stmt);
0771: }
0772: }
0773:
0774: /**
0775: * {@inheritDoc} *
0776: */
0777: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0778: public String getContent(long id, FxTreeMode mode)
0779: throws FxApplicationException {
0780: return _getContent(id, false, mode);
0781: }
0782:
0783: /**
0784: * {@inheritDoc} *
0785: */
0786: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0787: public String getFinalContent(long id, String masterTemplateFile,
0788: FxTreeMode mode) throws FxApplicationException {
0789: return _setMasterTemplateFile(_getContent(id, true, mode),
0790: masterTemplateFile);
0791: }
0792:
0793: /**
0794: * {@inheritDoc} *
0795: */
0796: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0797: public String getContent(String templateName, FxTreeMode mode)
0798: throws FxApplicationException {
0799: return _getContent(templateName, false);
0800: }
0801:
0802: /**
0803: * {@inheritDoc} *
0804: */
0805: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0806: // TODO: ???
0807: public String getFinalContent(String templateName,
0808: String masterTemplateFile) throws FxApplicationException {
0809: return _setMasterTemplateFile(_getContent(templateName, true),
0810: masterTemplateFile);
0811: }
0812:
0813: /**
0814: * Helper function, replaces the internal template handle by the provided one.
0815: *
0816: * @param content the content
0817: * @param masterTemplateFile the final template file
0818: * @return the processed content
0819: */
0820: private String _setMasterTemplateFile(String content,
0821: String masterTemplateFile) {
0822: if (masterTemplateFile == null) {
0823: return content;
0824: }
0825: return content
0826: .replaceFirst(
0827: "<ui:composition[\\s]*template[\\s]*=[\\s]*\"[^\"]*\">",
0828: "<ui:composition template=\"/"
0829: + masterTemplateFile + "\">");
0830: }
0831:
0832: /**
0833: * {@inheritDoc} *
0834: */
0835: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0836: private String _getContent(String templateName, boolean getFinal)
0837: throws FxApplicationException {
0838: Connection con = null;
0839: PreparedStatement ps = null;
0840: try {
0841: con = Database.getDbConnection();
0842: String selectCol = getFinal ? "ifnull(FINAL_CONTENT,content)"
0843: : "content";
0844: ps = con.prepareStatement("SELECT " + selectCol + " FROM "
0845: + TBL_TEMPLATE + " where name=?");
0846: ps.setString(1, templateName);
0847: ResultSet rs = ps.executeQuery();
0848: if (rs.next()) {
0849: return rs.getString(1);
0850: } else {
0851: return null;
0852: }
0853: } catch (Throwable t) {
0854: FxUpdateException exc = new FxUpdateException(t,
0855: "Template.err.loadContent.failed", templateName);
0856: LOG.error(exc);
0857: throw exc;
0858: } finally {
0859: Database.closeObjects(TreeEngineBean.class, con, ps);
0860: }
0861: }
0862:
0863: /**
0864: * {@inheritDoc} *
0865: */
0866: @TransactionAttribute(TransactionAttributeType.REQUIRED)
0867: public void setTemplateMappings(long nodeId,
0868: List<FxTemplateMapping> map) throws FxApplicationException {
0869: String encodedTemplate = null;
0870: if (map != null) {
0871: encodedTemplate = "";
0872: for (FxTemplateMapping m : map) {
0873: String type = m.getContentType() == null ? "*" : m
0874: .getContentType().toString();
0875: encodedTemplate += ((encodedTemplate.length() == 0) ? ""
0876: : ";")
0877: + type + ":" + m.getTemplateId();
0878: }
0879: }
0880: Connection con = null;
0881: try {
0882: con = Database.getDbConnection();
0883: //TODO: Edit Tree??
0884: StorageManager.getTreeStorage().setTemplate(con,
0885: FxTreeMode.Edit, nodeId, encodedTemplate);
0886: } catch (Throwable t) {
0887: ctx.setRollbackOnly();
0888: FxUpdateException exc = new FxUpdateException(t,
0889: "ex.tree.setTemplate.failed", nodeId); // TODO
0890: LOG.error(exc);
0891: throw exc;
0892: } finally {
0893: Database.closeObjects(TreeEngineBean.class, con, null);
0894: }
0895: }
0896:
0897: /**
0898: * {@inheritDoc} *
0899: */
0900: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0901: public ArrayList<FxTemplateMapping> getTemplateMappings(
0902: long treeNodeId, FxTreeMode mode)
0903: throws FxApplicationException {
0904: FxTreeNode node = new TreeEngineBean()
0905: .getNode(mode, treeNodeId);
0906: if (node.getTemplate() == null
0907: || node.getTemplate().length() == 0) {
0908: return new ArrayList<FxTemplateMapping>(0);
0909: }
0910:
0911: ArrayList<FxTemplateMapping> result = new ArrayList<FxTemplateMapping>(
0912: 25);
0913: for (String templateMap : node.getTemplate().split(";")) {
0914: String decode[] = templateMap.split(":");
0915: FxTemplateMapping mp = new FxTemplateMapping(decode[0]
0916: .equals("*") ? null : Long.valueOf(decode[0]), Long
0917: .valueOf(decode[1]));
0918: result.add(mp);
0919: }
0920: return result;
0921:
0922: }
0923:
0924: /**
0925: * {@inheritDoc} *
0926: */
0927: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
0928: public FxTemplateInfo getTemplate(long treeNodeId, FxTreeMode mode)
0929: throws FxApplicationException {
0930: Connection con = null;
0931: Statement stmt = null;
0932: long contentType = 0;
0933: long contentId = -1;
0934: long templateId = -1;
0935: long parentNode = -1;
0936: String encodedTemplates = null;
0937: try {
0938: con = Database.getDbConnection();
0939: stmt = con.createStatement();
0940: final String TBL_TREE = "FX_TREE"
0941: + (mode == Live ? "L" : "");
0942: final String VERSION = mode == Live ? "islive_ver=true"
0943: : "ismax_ver=true";
0944: ResultSet rs = stmt
0945: .executeQuery(" select c.tdef,t.ref, getTemplates(t.id,false),t.parent from "
0946: + TBL_CONTENT
0947: + " c,"
0948: + TBL_TREE
0949: + " t where "
0950: + "t.id="
0951: + treeNodeId
0952: + " and t.ref=c.id and c." + VERSION);
0953: if (rs.next()) {
0954: contentType = rs.getLong(1);
0955: contentId = rs.getLong(2);
0956: // Read the encoded template String (eg. "infotypeId1:template1,infotypeId2:template2,....")
0957: encodedTemplates = rs.getString(3);
0958: parentNode = rs.getLong(4);
0959: if (rs.wasNull())
0960: parentNode = -1;
0961: }
0962: // No templates defined at all?
0963: if (encodedTemplates == null) {
0964: return null;
0965: }
0966: // Determine if any template fits
0967: String sct = contentType + ":";
0968: long fallbackTemplate = -1;
0969: for (String encodedTemplate : encodedTemplates.split(",")) {
0970: for (String templateMap : encodedTemplate.split(";")) {
0971: if (templateMap.startsWith("*:")) {
0972: if (fallbackTemplate == -1) {
0973: fallbackTemplate = Long.valueOf(templateMap
0974: .split(":")[1]);
0975: }
0976: } else if (templateMap.startsWith(sct)) {
0977: templateId = Long.valueOf(templateMap
0978: .split(":")[1]);
0979: break;
0980: }
0981: }
0982: if (templateId != -1)
0983: break;
0984: }
0985:
0986: // Use fallback?
0987: if (templateId == -1) {
0988: templateId = fallbackTemplate;
0989: }
0990:
0991: // Return template
0992: FxTemplateInfo result;
0993: if (templateId == -1) {
0994: // No template found for the node, still return a info object
0995: // whith the parent node, content id and content type infos
0996: result = new FxTemplateInfo(null, mode == Live,
0997: mode == Live, false);
0998: } else {
0999: // Load the template data
1000: result = getInfo(templateId, mode);
1001: }
1002: result.setParentNode(parentNode);
1003: result.setContentId(contentId);
1004: result.setTdef(contentType);
1005: return result;
1006: } catch (Throwable t) {
1007: FxUpdateException exc = new FxUpdateException(t,
1008: "Template.err.loadForTreeNode.failed", treeNodeId);
1009: LOG.error(exc);
1010: throw exc;
1011: } finally {
1012: Database.closeObjects(TreeEngineBean.class, con, stmt);
1013: }
1014: }
1015:
1016: }
|