0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/content/tags/sakai_2-4-1/content-impl/impl/src/java/org/sakaiproject/content/impl/DbContentService.java $
0003: * $Id: DbContentService.java 29603 2007-04-26 13:54:22Z ajpoland@iupui.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006, 2007 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.content.impl;
0021:
0022: import java.io.ByteArrayOutputStream;
0023: import java.io.File;
0024: import java.io.FileInputStream;
0025: import java.io.FileOutputStream;
0026: import java.io.IOException;
0027: import java.io.InputStream;
0028: import java.io.OutputStream;
0029: import java.nio.channels.FileChannel;
0030: import java.sql.Connection;
0031: import java.sql.ResultSet;
0032: import java.util.Collection;
0033: import java.util.Iterator;
0034: import java.util.List;
0035: import java.util.Stack;
0036:
0037: import org.apache.commons.logging.Log;
0038: import org.apache.commons.logging.LogFactory;
0039: import org.sakaiproject.component.cover.ComponentManager;
0040: import org.sakaiproject.content.api.ContentCollection;
0041: import org.sakaiproject.content.api.ContentCollectionEdit;
0042: import org.sakaiproject.content.api.ContentResource;
0043: import org.sakaiproject.content.api.ContentResourceEdit;
0044: import org.sakaiproject.content.api.LockManager;
0045: import org.sakaiproject.db.api.SqlReader;
0046: import org.sakaiproject.db.api.SqlService;
0047: import org.sakaiproject.entity.api.ResourceProperties;
0048: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
0049: import org.sakaiproject.exception.IdInvalidException;
0050: import org.sakaiproject.exception.IdLengthException;
0051: import org.sakaiproject.exception.IdUniquenessException;
0052: import org.sakaiproject.exception.IdUnusedException;
0053: import org.sakaiproject.exception.OverQuotaException;
0054: import org.sakaiproject.exception.PermissionException;
0055: import org.sakaiproject.exception.ServerOverloadException;
0056: import org.sakaiproject.exception.TypeException;
0057: import org.sakaiproject.id.api.IdManager;
0058: import org.sakaiproject.time.api.Time;
0059: import org.sakaiproject.time.cover.TimeService;
0060: import org.sakaiproject.util.BaseDbSingleStorage;
0061: import org.sakaiproject.util.StorageUser;
0062: import org.sakaiproject.util.Xml;
0063: import org.w3c.dom.Document;
0064: import org.w3c.dom.Element;
0065:
0066: /**
0067: * <p>
0068: * DbContentService is an extension of the BaseContentService with a database
0069: * implementation.
0070: * </p>
0071: * <p>
0072: * The sql scripts in src/sql/chef_content.sql must be run on the database.
0073: * </p>
0074: */
0075: public class DbContentService extends BaseContentService {
0076: /** Our logger. */
0077: private static Log M_log = LogFactory
0078: .getLog(DbContentService.class);
0079:
0080: /** Table name for collections. */
0081: protected String m_collectionTableName = "CONTENT_COLLECTION";
0082:
0083: /** Table name for resources. */
0084: protected String m_resourceTableName = "CONTENT_RESOURCE";
0085:
0086: /** Table name for resources. */
0087: protected String m_resourceBodyTableName = "CONTENT_RESOURCE_BODY_BINARY";
0088:
0089: /** Table name for entity-group relationships. */
0090: protected String m_groupTableName = "CONTENT_ENTITY_GROUPS";
0091:
0092: /**
0093: * If true, we do our locks in the remote database, otherwise we do them
0094: * here.
0095: */
0096: protected boolean m_locksInDb = true;
0097:
0098: /** The extra field(s) to write to the database - collections. */
0099: protected static final String[] COLLECTION_FIELDS = { "IN_COLLECTION" };
0100:
0101: /**
0102: * The extra field(s) to write to the database - resources - when we are
0103: * doing bodys in files.
0104: */
0105: protected static final String[] RESOURCE_FIELDS_FILE = {
0106: "IN_COLLECTION", "FILE_PATH" };
0107:
0108: /**
0109: * The extra field(s) to write to the database - resources - when we are
0110: * doing bodys the db.
0111: */
0112: protected static final String[] RESOURCE_FIELDS = { "IN_COLLECTION" };
0113:
0114: /** Table name for resources delete. */
0115: protected String m_resourceDeleteTableName = "CONTENT_RESOURCE_DELETE";
0116:
0117: /** Table name for resources delete. */
0118: protected String m_resourceBodyDeleteTableName = "CONTENT_RESOURCE_BODY_BINARY_DELETE";
0119:
0120: /** The chunk size used when streaming (100k). */
0121: protected static final int STREAM_BUFFER_SIZE = 102400;
0122:
0123: /***************************************************************************
0124: * Constructors, Dependencies and their setter methods
0125: **************************************************************************/
0126:
0127: /** Dependency: LockManager */
0128: LockManager m_lockManager = null;
0129:
0130: /**
0131: * Dependency: LockManager
0132: *
0133: * @param service
0134: * The LockManager
0135: */
0136: public void setLockManager(LockManager lockManager) {
0137: m_lockManager = lockManager;
0138: }
0139:
0140: /** Dependency: SqlService */
0141: protected SqlService m_sqlService = null;
0142:
0143: /**
0144: * Dependency: SqlService.
0145: *
0146: * @param service
0147: * The SqlService.
0148: */
0149: public void setSqlService(SqlService service) {
0150: m_sqlService = service;
0151: }
0152:
0153: /**
0154: * Configuration: set the table name for collections.
0155: *
0156: * @param path
0157: * The table name for collections.
0158: */
0159: public void setCollectionTableName(String name) {
0160: m_collectionTableName = name;
0161: }
0162:
0163: /**
0164: * Configuration: set the table name for resources.
0165: *
0166: * @param path
0167: * The table name for resources.
0168: */
0169: public void setResourceTableName(String name) {
0170: m_resourceTableName = name;
0171: }
0172:
0173: /**
0174: * Configuration: set the table name for resource body.
0175: *
0176: * @param path
0177: * The table name for resource body.
0178: */
0179: public void setResourceBodyTableName(String name) {
0180: m_resourceBodyTableName = name;
0181: }
0182:
0183: /**
0184: * Configuration: set the locks-in-db
0185: *
0186: * @param value
0187: * The locks-in-db value.
0188: */
0189: public void setLocksInDb(String value) {
0190: m_locksInDb = new Boolean(value).booleanValue();
0191: }
0192:
0193: /** Set if we are to run the to-file conversion. */
0194: protected boolean m_convertToFile = false;
0195:
0196: /**
0197: * Configuration: run the to-file conversion.
0198: *
0199: * @param value
0200: * The conversion desired value.
0201: */
0202: public void setConvertToFile(String value) {
0203: m_convertToFile = new Boolean(value).booleanValue();
0204: }
0205:
0206: /** Configuration: to run the ddl on init or not. */
0207: protected boolean m_autoDdl = false;
0208:
0209: /* Virtual Content Hosting Handler -- handler which resolves virtual entities to real ones */
0210: private ContentHostingHandlerResolverImpl contentHostingHandlerResolver = null;
0211:
0212: /**
0213: * Configuration: to run the ddl on init or not.
0214: *
0215: * @param value
0216: * the auto ddl value.
0217: */
0218: public void setAutoDdl(String value) {
0219: m_autoDdl = new Boolean(value).booleanValue();
0220: }
0221:
0222: // htripath-start
0223: public void setResourceDeleteTableName(String name) {
0224: m_resourceDeleteTableName = name;
0225: }
0226:
0227: public void setResourceBodyDeleteTableName(String name) {
0228: m_resourceBodyDeleteTableName = name;
0229: }
0230:
0231: // htripath-end
0232:
0233: public void setEntityGroupTableName(String name) {
0234: m_groupTableName = name;
0235: }
0236:
0237: /***************************************************************************
0238: * Init and Destroy
0239: **************************************************************************/
0240:
0241: /**
0242: * Final initialization, once all dependencies are set.
0243: */
0244: public void init() {
0245: try {
0246: // if we are auto-creating our schema, check and create
0247: if (m_autoDdl) {
0248: m_sqlService.ddl(this .getClass().getClassLoader(),
0249: "sakai_content");
0250:
0251: // add the delete table
0252: m_sqlService.ddl(this .getClass().getClassLoader(),
0253: "sakai_content_delete");
0254:
0255: // do the 2.1.0 conversions
0256: m_sqlService.ddl(this .getClass().getClassLoader(),
0257: "sakai_content_2_1_0");
0258: }
0259:
0260: super .init();
0261:
0262: // convert?
0263: if (m_convertToFile) {
0264: m_convertToFile = false;
0265: convertToFile();
0266: }
0267:
0268: M_log.info("init(): tables: " + m_collectionTableName + " "
0269: + m_resourceTableName + " "
0270: + m_resourceBodyTableName + " " + m_groupTableName
0271: + " locks-in-db: " + m_locksInDb + " bodyPath: "
0272: + m_bodyPath);
0273: } catch (Throwable t) {
0274: M_log.warn("init(): ", t);
0275: }
0276: }
0277:
0278: /**
0279: *
0280: */
0281: private int countQuery(String sql, String param)
0282: throws IdUnusedException {
0283:
0284: Object[] fields = new Object[1];
0285: fields[0] = param;
0286:
0287: List list = m_sqlService.dbRead(sql, fields, null);
0288:
0289: if (list != null) {
0290: int rv = 0;
0291: Iterator iter = list.iterator();
0292: if (iter.hasNext()) {
0293: try {
0294: Object val = iter.next();
0295: rv = Integer.parseInt((String) val);
0296: } catch (Exception ignore) {
0297: }
0298: }
0299: return rv;
0300: }
0301: throw new IdUnusedException(param);
0302: }
0303:
0304: public int getCollectionSize(String id) throws IdUnusedException,
0305: TypeException, PermissionException {
0306:
0307: /*
0308: * Note: Content Hosting Handler This will only count local collection
0309: * information For the moment its only used by setPriority
0310: */
0311: String wildcard;
0312:
0313: if (id.endsWith("/")) {
0314: wildcard = id + "%";
0315: } else {
0316: wildcard = id + "/%";
0317: }
0318:
0319: int fileCount = countQuery(
0320: "select count(IN_COLLECTION) from CONTENT_RESOURCE where IN_COLLECTION like ?",
0321: wildcard);
0322: int folderCount = countQuery(
0323: "select count(IN_COLLECTION) from CONTENT_COLLECTION where IN_COLLECTION like ?",
0324: wildcard);
0325: ;
0326: return fileCount + folderCount;
0327: }
0328:
0329: /***************************************************************************
0330: * UUID Support
0331: **************************************************************************/
0332:
0333: /**
0334: * For a given id, return its UUID (creating it if it does not already
0335: * exist)
0336: */
0337:
0338: public String getUuid(String id) {
0339:
0340: /*
0341: * Note: Content Hosting Handler This will only operate on local
0342: * resources The only thing that may not work is move.
0343: */
0344: String uuid = null;
0345:
0346: uuid = findUuid(id);
0347:
0348: if (uuid != null)
0349: return uuid;
0350:
0351: // UUID not found, so create one and store it
0352:
0353: IdManager uuidManager = (IdManager) ComponentManager
0354: .get(IdManager.class);
0355: uuid = uuidManager.createUuid();
0356:
0357: setUuidInternal(id, uuid);
0358:
0359: return uuid;
0360: }
0361:
0362: /**
0363: * @param id
0364: * id of the resource to set the UUID for
0365: * @param uuid
0366: * the new UUID of the resource
0367: * @throws IdInvalidException
0368: * if the given resource already has a UUID set
0369: */
0370: public void setUuid(String id, String uuid)
0371: throws IdInvalidException {
0372: String existingUuid = findUuid(id);
0373: if (existingUuid != null) {
0374: throw new IdInvalidException(id);
0375: }
0376:
0377: setUuidInternal(id, uuid);
0378: }
0379:
0380: protected void setUuidInternal(String id, String uuid) {
0381: try {
0382: // get a connection for the updates
0383: final Connection connection = m_sqlService
0384: .borrowConnection();
0385: boolean wasCommit = connection.getAutoCommit();
0386: connection.setAutoCommit(false);
0387:
0388: // set any existing one to null
0389: String sql = "update CONTENT_RESOURCE set RESOURCE_UUID = ? where RESOURCE_UUID = ?";
0390: Object[] fields = new Object[2];
0391: fields[0] = null;
0392: fields[1] = uuid;
0393: m_sqlService.dbWrite(connection, sql, fields);
0394:
0395: sql = "update CONTENT_RESOURCE set RESOURCE_UUID = ? where RESOURCE_ID = ?";
0396: fields = new Object[2];
0397: fields[0] = uuid;
0398: fields[1] = id;
0399: m_sqlService.dbWrite(connection, sql, fields);
0400:
0401: connection.commit();
0402: connection.setAutoCommit(wasCommit);
0403: m_sqlService.returnConnection(connection);
0404: } catch (Throwable t) {
0405: M_log.warn("getUuid: failed: " + t);
0406: }
0407: }
0408:
0409: /**
0410: * private utility method to search for UUID for given id
0411: */
0412:
0413: private String findUuid(String id) {
0414: String sql = "select RESOURCE_UUID from CONTENT_RESOURCE where RESOURCE_ID=?";
0415: Object[] fields = new Object[1];
0416: fields[0] = id;
0417:
0418: String uuid = null;
0419: List result = m_sqlService.dbRead(sql, fields, null);
0420:
0421: if (result != null) {
0422: Iterator iter = result.iterator();
0423: if (iter.hasNext()) {
0424: uuid = (String) iter.next();
0425: }
0426: }
0427:
0428: return uuid;
0429: }
0430:
0431: /**
0432: * For a given UUID, attempt to lookup and return the corresponding id (URI)
0433: */
0434:
0435: public String resolveUuid(String uuid) {
0436:
0437: String id = null;
0438:
0439: try {
0440: String sql = "select RESOURCE_ID from CONTENT_RESOURCE where RESOURCE_UUID=?";
0441: Object[] fields = new Object[1];
0442: fields[0] = uuid;
0443:
0444: List result = m_sqlService.dbRead(sql, fields, null);
0445:
0446: if (result != null) {
0447: Iterator iter = result.iterator();
0448: if (iter.hasNext()) {
0449: id = (String) iter.next();
0450: }
0451: }
0452: } catch (Throwable t) {
0453: M_log.warn("resolveUuid: failed: " + t);
0454: }
0455: return id;
0456: }
0457:
0458: /***************************************************************************
0459: * BaseContentService extensions
0460: **************************************************************************/
0461:
0462: /**
0463: * Construct a Storage object.
0464: *
0465: * @return The new storage object.
0466: */
0467: protected Storage newStorage() {
0468: return new DbStorage(new CollectionStorageUser(),
0469: new ResourceStorageUser(), (m_bodyPath != null),
0470: contentHostingHandlerResolver);
0471:
0472: } // newStorage
0473:
0474: /***************************************************************************
0475: * Storage implementation
0476: **************************************************************************/
0477: protected class DbStorage implements Storage {
0478: /** A storage for collections. */
0479: protected BaseDbSingleStorage m_collectionStore = null;
0480:
0481: /** A storage for resources. */
0482: protected BaseDbSingleStorage m_resourceStore = null;
0483:
0484: /** htripath- Storage for resources delete */
0485: protected BaseDbSingleStorage m_resourceDeleteStore = null;
0486:
0487: protected BaseContentHostingHandlerResolver resolver = null;
0488:
0489: private ThreadLocal stackMarker = new ThreadLocal();
0490:
0491: /**
0492: * Construct.
0493: *
0494: * @param collectionUser
0495: * The StorageUser class to call back for creation of collection objects.
0496: * @param resourceUser
0497: * The StorageUser class to call back for creation of resource objects.
0498: */
0499: public DbStorage(StorageUser collectionUser,
0500: StorageUser resourceUser, boolean bodyInFile,
0501: BaseContentHostingHandlerResolver resolver) {
0502: this .resolver = resolver;
0503: this .resolver.setResourceUser(resourceUser);
0504: this .resolver.setCollectionUser(collectionUser);
0505:
0506: // build the collection store - a single level store
0507: m_collectionStore = new BaseDbSingleStorage(
0508: m_collectionTableName, "COLLECTION_ID",
0509: COLLECTION_FIELDS, m_locksInDb, "collection",
0510: collectionUser, m_sqlService);
0511:
0512: // build the resources store - a single level store
0513: m_resourceStore = new BaseDbSingleStorage(
0514: m_resourceTableName, "RESOURCE_ID",
0515: (bodyInFile ? RESOURCE_FIELDS_FILE
0516: : RESOURCE_FIELDS), m_locksInDb,
0517: "resource", resourceUser, m_sqlService);
0518:
0519: // htripath-build the resource for store of deleted record-single
0520: // level store
0521: m_resourceDeleteStore = new BaseDbSingleStorage(
0522: m_resourceDeleteTableName, "RESOURCE_ID",
0523: (bodyInFile ? RESOURCE_FIELDS_FILE
0524: : RESOURCE_FIELDS), m_locksInDb,
0525: "resource", resourceUser, m_sqlService);
0526:
0527: } // DbStorage
0528:
0529: /**
0530: * Open and be ready to read / write.
0531: */
0532: public void open() {
0533: m_collectionStore.open();
0534: m_resourceStore.open();
0535: m_resourceDeleteStore.open();
0536: } // open
0537:
0538: /**
0539: * Close.
0540: */
0541: public void close() {
0542: m_collectionStore.close();
0543: m_resourceStore.close();
0544: m_resourceDeleteStore.close();
0545: } // close
0546:
0547: private class StackRef {
0548: protected int count = 0;
0549: }
0550:
0551: /**
0552: * increase the stack counter and return true if this is the top of the stack
0553: *
0554: * @return
0555: */
0556: private boolean in() {
0557: StackRef r = (StackRef) stackMarker.get();
0558: if (r == null) {
0559: r = new StackRef();
0560: stackMarker.set(r);
0561: }
0562: r.count++;
0563: return r.count <= 1;// johnf@caret -- used to permit no self-recurses; now permits 0 or 2 (r.count == 1);
0564: }
0565:
0566: /**
0567: * decrement the stack counter on the thread
0568: */
0569: private void out() {
0570: StackRef r = (StackRef) stackMarker.get();
0571: if (r == null) {
0572: r = new StackRef();
0573: stackMarker.set(r);
0574: }
0575: r.count--;
0576: if (r.count < 0) {
0577: r.count = 0;
0578: }
0579: }
0580:
0581: /** Collections * */
0582:
0583: public boolean checkCollection(String id) {
0584: if (id == null || id.trim().length() == 0) {
0585: return false;
0586: }
0587: boolean goin = in();
0588: try {
0589: if (resolver != null && goin) {
0590: return resolver.checkCollection(this , id);
0591: } else {
0592: return m_collectionStore.checkResource(id);
0593: }
0594: } finally {
0595: out();
0596: }
0597: }
0598:
0599: public ContentCollection getCollection(String id) {
0600: if (id == null || id.trim().length() == 0) {
0601: return null;
0602: }
0603: boolean goin = in();
0604: try {
0605: if (resolver != null && goin) {
0606: return resolver.getCollection(this , id);
0607: } else {
0608: return (ContentCollection) m_collectionStore
0609: .getResource(id);
0610: }
0611: } finally {
0612: out();
0613: }
0614:
0615: }
0616:
0617: /**
0618: * Get a list of all getCollections within a collection.
0619: */
0620: public List getCollections(ContentCollection collection) {
0621: boolean goin = in();
0622: try {
0623: if (resolver != null && goin) {
0624: return resolver.getCollections(this , collection);
0625: } else {
0626: // limit to those whose reference path (based on id) matches
0627: // the
0628: // collection id
0629: final String target = collection.getId();
0630:
0631: /*
0632: * // read all the records, then filter them to accept only those in this collection // Note: this is not desirable, as the read is linear to the database site -ggolden List rv = m_collectionStore.getSelectedResources( new Filter() {
0633: * public boolean accept(Object o) { // o is a String, the collection id return StringUtil.referencePath((String) o).equals(target); } } );
0634: */
0635:
0636: // read the records with a where clause to let the database
0637: // select
0638: // those in this collection
0639: return m_collectionStore.getAllResourcesWhere(
0640: "IN_COLLECTION", target);
0641: }
0642: } finally {
0643: out();
0644: }
0645:
0646: } // getCollections
0647:
0648: public ContentCollectionEdit putCollection(String id) {
0649: if (id == null || id.trim().length() == 0) {
0650: return null;
0651: }
0652: boolean goin = in();
0653: try {
0654: if (resolver != null && goin) {
0655: return (ContentCollectionEdit) resolver
0656: .putCollection(this , id);
0657: } else {
0658: return (ContentCollectionEdit) m_collectionStore
0659: .putResource(id, null);
0660: }
0661: } finally {
0662: out();
0663: }
0664: }
0665:
0666: public ContentCollectionEdit editCollection(String id) {
0667: if (id == null || id.trim().length() == 0) {
0668: return null;
0669: }
0670: boolean goin = in();
0671: try {
0672: if (resolver != null && goin) {
0673: return (ContentCollectionEdit) resolver
0674: .editCollection(this , id);
0675: } else {
0676: return (ContentCollectionEdit) m_collectionStore
0677: .editResource(id);
0678: }
0679: } finally {
0680: out();
0681: }
0682: }
0683:
0684: // protected String externalResourceDeleteFileName(ContentResource resource)
0685: // {
0686: // return m_bodyPath + "/delete/" + ((BaseResourceEdit) resource).m_filePath;
0687: // }
0688:
0689: // htripath -end
0690:
0691: public void cancelResource(ContentResourceEdit edit) {
0692: boolean goin = in();
0693: try {
0694: if (resolver != null && goin) {
0695: resolver.cancelResource(this , edit);
0696: } else {
0697: // clear the memory image of the body
0698: byte[] body = ((BaseResourceEdit) edit).m_body;
0699: ((BaseResourceEdit) edit).m_body = null;
0700: m_resourceStore.cancelResource(edit);
0701:
0702: }
0703: } finally {
0704: out();
0705: }
0706: }
0707:
0708: public void commitCollection(ContentCollectionEdit edit) {
0709: boolean goin = in();
0710: try {
0711: if (resolver != null && goin) {
0712: resolver.commitCollection(this , edit);
0713: } else {
0714: m_collectionStore.commitResource(edit);
0715: }
0716: } finally {
0717: out();
0718: }
0719: }
0720:
0721: public void cancelCollection(ContentCollectionEdit edit) {
0722: boolean goin = in();
0723: try {
0724: if (resolver != null && goin) {
0725: resolver.cancelCollection(this , edit);
0726: } else {
0727: m_collectionStore.cancelResource(edit);
0728: }
0729: } finally {
0730: out();
0731: }
0732:
0733: }
0734:
0735: public void removeCollection(ContentCollectionEdit edit) {
0736: boolean goin = in();
0737: try {
0738: if (resolver != null && goin) {
0739: resolver.removeCollection(this , edit);
0740: } else {
0741: m_collectionStore.removeResource(edit);
0742: }
0743: } finally {
0744: out();
0745: }
0746: }
0747:
0748: /** Resources * */
0749:
0750: public boolean checkResource(String id) {
0751: if (id == null || id.trim().length() == 0) {
0752: return false;
0753: }
0754: boolean goin = in();
0755: try {
0756: if (resolver != null && goin) {
0757: return resolver.checkResource(this , id);
0758: } else {
0759: return m_resourceStore.checkResource(id);
0760: }
0761: } finally {
0762: out();
0763: }
0764: }
0765:
0766: public ContentResource getResource(String id) {
0767: if (id == null || id.trim().length() == 0) {
0768: return null;
0769: }
0770: boolean goin = in();
0771: try {
0772: if (resolver != null && goin) {
0773: return (ContentResource) resolver.getResource(this ,
0774: id);
0775: } else {
0776: return (ContentResource) m_resourceStore
0777: .getResource(id);
0778: }
0779: } finally {
0780: out();
0781: }
0782: }
0783:
0784: public List getResources(ContentCollection collection) {
0785: boolean goin = in();
0786: try {
0787: if (resolver != null && goin) {
0788: return resolver.getResources(this , collection);
0789: } else {
0790: // limit to those whose reference path (based on id) matches
0791: // the
0792: // collection id
0793: final String target = collection.getId();
0794:
0795: /*
0796: * // read all the records, then filter them to accept only those in this collection // Note: this is not desirable, as the read is linear to the database site -ggolden List rv = m_resourceStore.getSelectedResources( new Filter() {
0797: * public boolean accept(Object o) { // o is a String, the resource id return StringUtil.referencePath((String) o).equals(target); } } );
0798: */
0799:
0800: // read the records with a where clause to let the database
0801: // select
0802: // those in this collection
0803: return m_resourceStore.getAllResourcesWhere(
0804: "IN_COLLECTION", target);
0805: }
0806: } finally {
0807: out();
0808: }
0809:
0810: } // getResources
0811:
0812: public List getFlatResources(String collectionId) {
0813: List rv = null;
0814: boolean goin = in();
0815: try {
0816: if (resolver != null && goin) {
0817: rv = resolver.getFlatResources(this , collectionId);
0818: } else {
0819: rv = m_resourceStore.getAllResourcesWhereLike(
0820: "IN_COLLECTION", collectionId + "%");
0821: }
0822: return rv;
0823: } finally {
0824: out();
0825: }
0826: }
0827:
0828: public ContentResourceEdit putResource(String id) {
0829: if (id == null || id.trim().length() == 0) {
0830: return null;
0831: }
0832: boolean goin = in();
0833: try {
0834: if (resolver != null && goin) {
0835: return (ContentResourceEdit) resolver.putResource(
0836: this , id);
0837: } else {
0838: return (ContentResourceEdit) m_resourceStore
0839: .putResource(id, null);
0840: }
0841: } finally {
0842: out();
0843: }
0844: }
0845:
0846: public ContentResourceEdit editResource(String id) {
0847: if (id == null || id.trim().length() == 0) {
0848: return null;
0849: }
0850: boolean goin = in();
0851: try {
0852: if (resolver != null && goin) {
0853: return (ContentResourceEdit) resolver.editResource(
0854: this , id);
0855: } else {
0856: return (ContentResourceEdit) m_resourceStore
0857: .editResource(id);
0858: }
0859: } finally {
0860: out();
0861: }
0862: }
0863:
0864: public void commitResource(ContentResourceEdit edit)
0865: throws ServerOverloadException {
0866: // keep the body out of the XML
0867:
0868: boolean goin = in();
0869: try {
0870: if (resolver != null && goin) {
0871: resolver.commitResource(this , edit);
0872: } else {
0873: BaseResourceEdit redit = (BaseResourceEdit) edit;
0874: if (redit.m_body == null) {
0875: if (redit.m_contentStream == null) {
0876: // no body and no stream -- may result from edit in which body is not accessed or modified
0877: M_log
0878: .info("ContentResource committed with no change to contents (i.e. no body and no stream for content): "
0879: + edit.getReference());
0880: } else {
0881: // if we have been configured to use an external file system
0882: if (m_bodyPath != null) {
0883: boolean ok = putResourceBodyFilesystem(
0884: edit, redit.m_contentStream);
0885: if (!ok) {
0886: cancelResource(edit);
0887: throw new ServerOverloadException(
0888: "failed to write file");
0889: }
0890: }
0891:
0892: // otherwise use the database
0893: else {
0894: putResourceBodyDb(edit,
0895: redit.m_contentStream);
0896: }
0897: }
0898: } else {
0899: byte[] body = ((BaseResourceEdit) edit).m_body;
0900: ((BaseResourceEdit) edit).m_body = null;
0901:
0902: // update the resource body
0903: if (body != null) {
0904: // if we have been configured to use an external file
0905: // system
0906: if (m_bodyPath != null) {
0907: boolean ok = putResourceBodyFilesystem(
0908: edit, body);
0909: if (!ok) {
0910: cancelResource(edit);
0911: throw new ServerOverloadException(
0912: "failed to write file");
0913: }
0914: }
0915:
0916: // otherwise use the database
0917: else {
0918: putResourceBodyDb(edit, body);
0919: }
0920: }
0921: }
0922: m_resourceStore.commitResource(edit);
0923: }
0924:
0925: } finally {
0926: out();
0927: }
0928: }
0929:
0930: // htripath - start
0931: /** Add resource to content_resouce_delete table for user deleted resources */
0932: public ContentResourceEdit putDeleteResource(String id,
0933: String uuid, String userId) {
0934: boolean goin = in();
0935: try {
0936: if (resolver != null && goin) {
0937: return (ContentResourceEdit) resolver
0938: .putDeleteResource(this , id, uuid, userId);
0939: } else {
0940: return (ContentResourceEdit) m_resourceDeleteStore
0941: .putDeleteResource(id, uuid, userId, null);
0942: }
0943: } finally {
0944: out();
0945: }
0946: }
0947:
0948: /**
0949: * update xml and store the body of file TODO storing of body content is not used now.
0950: */
0951: public void commitDeleteResource(ContentResourceEdit edit,
0952: String uuid) {
0953: boolean goin = in();
0954: try {
0955: if (resolver != null && goin) {
0956: resolver.commitDeleteResource(this , edit, uuid);
0957: } else {
0958: byte[] body = ((BaseResourceEdit) edit).m_body;
0959: ((BaseResourceEdit) edit).m_body = null;
0960:
0961: // update properties in xml and delete locks
0962: m_resourceDeleteStore.commitDeleteResource(edit,
0963: uuid);
0964: }
0965: } finally {
0966: out();
0967: }
0968:
0969: }
0970:
0971: public void removeResource(ContentResourceEdit edit) {
0972: // delete the body
0973: boolean goin = in();
0974: try {
0975: if (resolver != null && goin) {
0976: resolver.removeResource(this , edit);
0977: } else {
0978:
0979: // if we have been configured to use an external file system
0980: if (m_bodyPath != null) {
0981: delResourceBodyFilesystem(edit);
0982: }
0983:
0984: // otherwise use the database
0985: else {
0986: delResourceBodyDb(edit);
0987: }
0988:
0989: // clear the memory image of the body
0990: byte[] body = ((BaseResourceEdit) edit).m_body;
0991: ((BaseResourceEdit) edit).m_body = null;
0992:
0993: m_resourceStore.removeResource(edit);
0994:
0995: }
0996: } finally {
0997: out();
0998: }
0999:
1000: }
1001:
1002: /**
1003: * Read the resource's body.
1004: *
1005: * @param resource
1006: * The resource whose body is desired.
1007: * @return The resources's body content as a byte array.
1008: * @exception ServerOverloadException
1009: * if the server is configured to save the resource body in the filesystem and an error occurs while accessing the server's filesystem.
1010: */
1011: public byte[] getResourceBody(ContentResource resource)
1012: throws ServerOverloadException {
1013: boolean goin = in();
1014: try {
1015: if (resolver != null && goin) {
1016: return resolver.getResourceBody(this , resource);
1017: } else {
1018: if (((BaseResourceEdit) resource).m_contentLength <= 0) {
1019: M_log
1020: .warn("getResourceBody(): non-positive content length: "
1021: + ((BaseResourceEdit) resource).m_contentLength
1022: + " id: " + resource.getId());
1023: return null;
1024: }
1025:
1026: // if we have been configured to use an external file system
1027: if (m_bodyPath != null) {
1028: return getResourceBodyFilesystem(resource);
1029: }
1030:
1031: // otherwise use the database
1032: else {
1033: return getResourceBodyDb(resource);
1034: }
1035: }
1036: } finally {
1037: out();
1038: }
1039:
1040: }
1041:
1042: /**
1043: * Read the resource's body from the database.
1044: *
1045: * @param resource
1046: * The resource whose body is desired.
1047: * @return The resources's body content as a byte array.
1048: */
1049: protected byte[] getResourceBodyDb(ContentResource resource) {
1050: // get the resource from the db
1051: String sql = "select BODY from " + m_resourceBodyTableName
1052: + " where ( RESOURCE_ID = ? )";
1053:
1054: Object[] fields = new Object[1];
1055: fields[0] = resource.getId();
1056:
1057: // create the body to read into
1058: byte[] body = new byte[((BaseResourceEdit) resource).m_contentLength];
1059: m_sqlService.dbReadBinary(sql, fields, body);
1060:
1061: return body;
1062:
1063: }
1064:
1065: /**
1066: * Read the resource's body from the external file system.
1067: *
1068: * @param resource
1069: * The resource whose body is desired.
1070: * @return The resources's body content as a byte array.
1071: * @exception ServerOverloadException
1072: * if server is configured to store resource body in filesystem and error occurs trying to read from filesystem.
1073: */
1074: protected byte[] getResourceBodyFilesystem(
1075: ContentResource resource)
1076: throws ServerOverloadException {
1077: // form the file name
1078: File file = new File(externalResourceFileName(resource));
1079:
1080: // read the new
1081: try {
1082: byte[] body = new byte[((BaseResourceEdit) resource).m_contentLength];
1083: FileInputStream in = new FileInputStream(file);
1084:
1085: in.read(body);
1086: in.close();
1087:
1088: return body;
1089: } catch (Throwable t) {
1090: // If there is not supposed to be data in the file - simply return zero length byte array
1091: if (((BaseResourceEdit) resource).m_contentLength == 0) {
1092: return new byte[0];
1093: }
1094:
1095: // If we have a non-zero body length and reading failed, it is an error worth of note
1096: M_log.warn(": failed to read resource: "
1097: + resource.getId() + " len: "
1098: + ((BaseResourceEdit) resource).m_contentLength
1099: + " : " + t);
1100: throw new ServerOverloadException(
1101: "failed to read resource");
1102: // return null;
1103: }
1104:
1105: }
1106:
1107: // the body is already in the resource for this version of storage
1108: public InputStream streamResourceBody(ContentResource resource)
1109: throws ServerOverloadException {
1110: boolean goin = in();
1111: try {
1112: if (resolver != null && goin) {
1113: return resolver.streamResourceBody(this , resource);
1114: } else {
1115: if (((BaseResourceEdit) resource).m_contentLength <= 0) {
1116: M_log
1117: .warn("streamResourceBody(): non-positive content length: "
1118: + ((BaseResourceEdit) resource).m_contentLength
1119: + " id: " + resource.getId());
1120: return null;
1121: }
1122:
1123: // if we have been configured to use an external file system
1124: if (m_bodyPath != null) {
1125: return streamResourceBodyFilesystem(resource);
1126: }
1127:
1128: // otherwise use the database
1129: else {
1130: return streamResourceBodyDb(resource);
1131: }
1132: }
1133: } finally {
1134: out();
1135: }
1136: }
1137:
1138: /**
1139: * Return an input stream.
1140: *
1141: * @param resource -
1142: * the resource for the stream It is a non-fatal error for the file not to be readible as long as the resource's expected length is zero. A zero length body is indicated by returning null. We check for the body length *after* we try to read
1143: * the file. If the file is readible, we simply read it and return it as the body.
1144: */
1145:
1146: protected InputStream streamResourceBodyFilesystem(
1147: ContentResource resource)
1148: throws ServerOverloadException {
1149: // form the file name
1150: File file = new File(externalResourceFileName(resource));
1151:
1152: // read the new
1153: try {
1154: FileInputStream in = new FileInputStream(file);
1155: return in;
1156: } catch (Throwable t) {
1157: // If there is not supposed to be data in the file - simply return null
1158: if (((BaseResourceEdit) resource).m_contentLength == 0) {
1159: return null;
1160: }
1161:
1162: // If we have a non-zero body length and reading failed, it is an error worth of note
1163: M_log.warn(": failed to read resource: "
1164: + resource.getId() + " len: "
1165: + ((BaseResourceEdit) resource).m_contentLength
1166: + " : " + t);
1167: throw new ServerOverloadException(
1168: "failed to read resource body");
1169: // return null;
1170: }
1171: }
1172:
1173: /**
1174: * When resources are stored, zero length bodys are not placed in the table hence this routine will return a null when the particular resource body is not found
1175: */
1176: protected InputStream streamResourceBodyDb(
1177: ContentResource resource)
1178: throws ServerOverloadException {
1179: // get the resource from the db
1180: String sql = "select BODY from " + m_resourceBodyTableName
1181: + " where ( RESOURCE_ID = ? )";
1182:
1183: Object[] fields = new Object[1];
1184: fields[0] = resource.getId();
1185:
1186: // get the stream, set expectations that this could be big
1187: InputStream in = m_sqlService.dbReadBinary(sql, fields,
1188: true);
1189:
1190: return in;
1191: }
1192:
1193: /**
1194: * Write the resource body to the database table.
1195: *
1196: * @param resource
1197: * The resource whose body is being written.
1198: * @param body
1199: * The body bytes to write. If there is no body or the body is zero bytes, no entry is inserted into the table.
1200: */
1201: protected void putResourceBodyDb(ContentResourceEdit resource,
1202: byte[] body) {
1203:
1204: if ((body == null) || (body.length == 0))
1205: return;
1206:
1207: // delete the old
1208: String statement = "delete from " + m_resourceBodyTableName
1209: + " where resource_id = ? ";
1210:
1211: Object[] fields = new Object[1];
1212: fields[0] = resource.getId();
1213:
1214: m_sqlService.dbWrite(statement, fields);
1215:
1216: // add the new
1217: statement = "insert into " + m_resourceBodyTableName
1218: + " (RESOURCE_ID, BODY)" + " values (? , ? )";
1219:
1220: m_sqlService.dbWriteBinary(statement, fields, body, 0,
1221: body.length);
1222:
1223: /*
1224: * %%% BLOB code // read the record's blob and update statement = "select body from " + m_resourceTableName + " where ( resource_id = '" + Validator.escapeSql(resource.getId()) + "' ) for update"; Sql.dbReadBlobAndUpdate(statement,
1225: * ((BaseResource)resource).m_body);
1226: */
1227: }
1228:
1229: /**
1230: * @param edit
1231: * @param stream
1232: */
1233: protected void putResourceBodyDb(ContentResourceEdit edit,
1234: InputStream stream) {
1235: // Do not create the files for resources with zero length bodies
1236: if ((stream == null))
1237: return;
1238:
1239: ByteArrayOutputStream bstream = new ByteArrayOutputStream();
1240:
1241: int byteCount = 0;
1242:
1243: // chunk
1244: byte[] chunk = new byte[STREAM_BUFFER_SIZE];
1245: int lenRead;
1246: try {
1247: while ((lenRead = stream.read(chunk)) != -1) {
1248: bstream.write(chunk, 0, lenRead);
1249: byteCount += lenRead;
1250: }
1251:
1252: edit.setContentLength(byteCount);
1253: ResourcePropertiesEdit props = edit.getPropertiesEdit();
1254: props.addProperty(
1255: ResourceProperties.PROP_CONTENT_LENGTH, Long
1256: .toString(byteCount));
1257: if (edit.getContentType() != null) {
1258: props.addProperty(
1259: ResourceProperties.PROP_CONTENT_TYPE, edit
1260: .getContentType());
1261: }
1262: } catch (IOException e) {
1263: // TODO Auto-generated catch block
1264: M_log.warn("IOException ", e);
1265: } finally {
1266: if (stream != null) {
1267: try {
1268: stream.close();
1269: } catch (IOException e) {
1270: // TODO Auto-generated catch block
1271: M_log.warn("IOException ", e);
1272: }
1273: }
1274: }
1275:
1276: if (bstream != null && bstream.size() > 0) {
1277: putResourceBodyDb(edit, bstream.toByteArray());
1278: }
1279: }
1280:
1281: /**
1282: * @param edit
1283: * @param stream
1284: * @return
1285: */
1286: private boolean putResourceBodyFilesystem(
1287: ContentResourceEdit resource, InputStream stream) {
1288: // Do not create the files for resources with zero length bodies
1289: if ((stream == null))
1290: return true;
1291:
1292: // form the file name
1293: File file = new File(externalResourceFileName(resource));
1294:
1295: // delete the old
1296: if (file.exists()) {
1297: file.delete();
1298: }
1299:
1300: FileOutputStream out = null;
1301:
1302: // add the new
1303: try {
1304: // make sure all directories are there
1305: File container = file.getParentFile();
1306: if (container != null) {
1307: container.mkdirs();
1308: }
1309:
1310: // write the file
1311: out = new FileOutputStream(file);
1312:
1313: int byteCount = 0;
1314: // chunk
1315: byte[] chunk = new byte[STREAM_BUFFER_SIZE];
1316: int lenRead;
1317: while ((lenRead = stream.read(chunk)) != -1) {
1318: out.write(chunk, 0, lenRead);
1319: byteCount += lenRead;
1320: }
1321:
1322: resource.setContentLength(byteCount);
1323: ResourcePropertiesEdit props = resource
1324: .getPropertiesEdit();
1325: props.addProperty(
1326: ResourceProperties.PROP_CONTENT_LENGTH, Long
1327: .toString(byteCount));
1328: if (resource.getContentType() != null) {
1329: props.addProperty(
1330: ResourceProperties.PROP_CONTENT_TYPE,
1331: resource.getContentType());
1332: }
1333: }
1334: // catch (Throwable t)
1335: // {
1336: // M_log.warn(": failed to write resource: " + resource.getId() + " : " + t);
1337: // return false;
1338: // }
1339: catch (IOException e) {
1340: M_log.warn("IOException", e);
1341: return false;
1342: } finally {
1343: if (stream != null) {
1344: try {
1345: stream.close();
1346: } catch (IOException e) {
1347: // TODO Auto-generated catch block
1348: M_log.warn("IOException ", e);
1349: }
1350: }
1351:
1352: if (out != null) {
1353: try {
1354: out.close();
1355: } catch (IOException e) {
1356: // TODO Auto-generated catch block
1357: M_log.warn("IOException ", e);
1358: }
1359: }
1360: }
1361:
1362: return true;
1363: }
1364:
1365: /**
1366: * Write the resource body to the external file system. The file name is the m_bodyPath with the resource id appended.
1367: *
1368: * @param resource
1369: * The resource whose body is being written.
1370: * @param body
1371: * The body bytes to write. If there is no body or the body is zero bytes, no entry is inserted into the filesystem.
1372: */
1373: protected boolean putResourceBodyFilesystem(
1374: ContentResourceEdit resource, byte[] body) {
1375: // Do not create the files for resources with zero length bodies
1376: if ((body == null) || (body.length == 0))
1377: return true;
1378:
1379: // form the file name
1380: File file = new File(externalResourceFileName(resource));
1381:
1382: // delete the old
1383: if (file.exists()) {
1384: file.delete();
1385: }
1386:
1387: // add the new
1388: try {
1389: // make sure all directories are there
1390: File container = file.getParentFile();
1391: if (container != null) {
1392: container.mkdirs();
1393: }
1394:
1395: // write the file
1396: FileOutputStream out = new FileOutputStream(file);
1397: out.write(body);
1398: out.close();
1399: } catch (Throwable t) {
1400: M_log.warn(": failed to write resource: "
1401: + resource.getId() + " : " + t);
1402: return false;
1403: }
1404:
1405: return true;
1406: }
1407:
1408: /**
1409: * Delete the resource body from the database table.
1410: *
1411: * @param resource
1412: * The resource whose body is being deleted.
1413: */
1414: protected void delResourceBodyDb(ContentResourceEdit resource) {
1415: // delete the record
1416: String statement = "delete from " + m_resourceBodyTableName
1417: + " where resource_id = ?";
1418:
1419: Object[] fields = new Object[1];
1420: fields[0] = resource.getId();
1421:
1422: m_sqlService.dbWrite(statement, fields);
1423: }
1424:
1425: /**
1426: * Delete the resource body from the external file system. The file name is the m_bodyPath with the resource id appended.
1427: *
1428: * @param resource
1429: * The resource whose body is being written.
1430: */
1431: protected void delResourceBodyFilesystem(
1432: ContentResourceEdit resource) {
1433: // form the file name
1434: File file = new File(externalResourceFileName(resource));
1435:
1436: // delete
1437: if (file.exists()) {
1438: file.delete();
1439: }
1440: }
1441:
1442: public int getMemberCount(String collectionId) {
1443: if (collectionId == null
1444: || collectionId.trim().length() == 0) {
1445: return 0;
1446: }
1447: boolean goin = in();
1448: try {
1449: if (resolver != null && goin) {
1450: return resolver.getMemberCount(this , collectionId);
1451: } else {
1452:
1453: int fileCount = 0;
1454: try {
1455: fileCount = countQuery(
1456: "select count(IN_COLLECTION) from CONTENT_RESOURCE where IN_COLLECTION = ?",
1457: collectionId);
1458: } catch (IdUnusedException e) {
1459: // ignore -- means this is not a collection or the collection contains no files, so zero is right answer
1460: }
1461: int folderCount = 0;
1462: try {
1463: folderCount = countQuery(
1464: "select count(IN_COLLECTION) from CONTENT_COLLECTION where IN_COLLECTION = ?",
1465: collectionId);
1466: } catch (IdUnusedException e) {
1467: // ignore -- means this is not a collection or the collection contains no folders, so zero is right answer
1468: }
1469: ;
1470: return fileCount + folderCount;
1471: }
1472: } finally {
1473: out();
1474: }
1475: }
1476:
1477: } // DbStorage
1478:
1479: /**
1480: * Form the full file path+name used to store the resource body in an external file system.
1481: *
1482: * @param resource
1483: * The resource.
1484: * @return The resource external file name.
1485: */
1486: protected String externalResourceFileName(ContentResource resource) {
1487: return m_bodyPath + ((BaseResourceEdit) resource).m_filePath;
1488: }
1489:
1490: /** We allow these characters to go un-escaped into the file name. */
1491: static protected final String VALID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.";
1492:
1493: /**
1494: * Return file system safe escaped name, that's also unique if the initial id is unique. * Use only the name, not the path part of the id
1495: *
1496: * @param value
1497: * The id to escape.
1498: * @return value escaped.
1499: */
1500: protected String escapeResourceName(String id) {
1501: if (id == null)
1502: return null;
1503:
1504: try {
1505: StringBuffer buf = new StringBuffer();
1506: for (int i = 0; i < id.length(); i++) {
1507: char c = id.charAt(i);
1508:
1509: // if not valid, escape
1510: if (VALID_CHARS.indexOf(c) == -1) {
1511: // the escape character
1512: buf.append('_');
1513:
1514: // the character value.
1515: buf.append(Integer.toHexString(c));
1516: } else {
1517: buf.append(c);
1518: }
1519: }
1520:
1521: String rv = buf.toString();
1522: return rv;
1523: } catch (Exception e) {
1524: M_log.warn("escapeResourceName: ", e);
1525: return id;
1526: }
1527: }
1528:
1529: /**
1530: * Create a file system body binary for any content_resource record that has
1531: * a null file_path.
1532: */
1533: protected void convertToFile() {
1534: M_log.info("convertToFile");
1535:
1536: try {
1537: // get a connection for the updates
1538: final Connection connection = m_sqlService
1539: .borrowConnection();
1540: boolean wasCommit = connection.getAutoCommit();
1541: connection.setAutoCommit(false);
1542:
1543: // get a connection for reading binary
1544: final Connection sourceConnection = m_sqlService
1545: .borrowConnection();
1546:
1547: final Counter count = new Counter();
1548:
1549: // read content_resource records that have null file path
1550: String sql = "select RESOURCE_ID, XML from CONTENT_RESOURCE where FILE_PATH IS NULL";
1551: m_sqlService.dbRead(sql, null, new SqlReader() {
1552: public Object readSqlResultRecord(ResultSet result) {
1553: String id = null;
1554: try {
1555: // create the Resource from the db xml
1556: id = result.getString(1);
1557: String xml = result.getString(2);
1558: if (xml == null) {
1559: M_log.warn("convertToFile: null xml : "
1560: + id);
1561: return null;
1562: }
1563:
1564: // read the xml
1565: Document doc = Xml.readDocumentFromString(xml);
1566: if (doc == null) {
1567: M_log.warn("convertToFile: null xml doc : "
1568: + id);
1569: return null;
1570: }
1571:
1572: // verify the root element
1573: Element root = doc.getDocumentElement();
1574: if (!root.getTagName().equals("resource")) {
1575: M_log
1576: .warn("convertToFile: XML root element not resource: "
1577: + root.getTagName());
1578: return null;
1579: }
1580: BaseResourceEdit edit = new BaseResourceEdit(
1581: root);
1582:
1583: // zero length?
1584: if (edit.getContentLength() == 0) {
1585: M_log
1586: .warn("convertToFile: zero length body : "
1587: + id);
1588: return null;
1589: }
1590:
1591: // is it there?
1592: String sql = "select RESOURCE_ID from CONTENT_RESOURCE_BODY_BINARY where (RESOURCE_ID = ?)";
1593: Object[] fields = new Object[1];
1594: fields[0] = id;
1595: List found = m_sqlService.dbRead(
1596: sourceConnection, sql, fields, null);
1597: if ((found == null) || (found.size() == 0)) {
1598: // not found
1599: M_log
1600: .warn("convertToFile: body not found in source : "
1601: + id);
1602: return null;
1603: }
1604:
1605: // get the creation date (or modified date, or now)
1606: Time created = null;
1607: try {
1608: created = edit
1609: .getProperties()
1610: .getTimeProperty(
1611: ResourceProperties.PROP_CREATION_DATE);
1612: } catch (Exception any) {
1613: try {
1614: created = edit
1615: .getProperties()
1616: .getTimeProperty(
1617: ResourceProperties.PROP_MODIFIED_DATE);
1618: } catch (Exception e) {
1619: created = TimeService.newTime();
1620: }
1621: }
1622:
1623: // form the file name
1624: edit.setFilePath(created);
1625:
1626: // read the body from the source
1627: sql = "select BODY from CONTENT_RESOURCE_BODY_BINARY where (RESOURCE_ID = ?)";
1628: byte[] body = new byte[edit.m_contentLength];
1629: m_sqlService.dbReadBinary(sourceConnection,
1630: sql, fields, body);
1631:
1632: // write the body to the file
1633: boolean ok = ((DbStorage) m_storage)
1634: .putResourceBodyFilesystem(edit, body);
1635: if (!ok) {
1636: M_log
1637: .warn("convertToFile: body file failure : "
1638: + id
1639: + " file: "
1640: + edit.m_filePath);
1641: return null;
1642: }
1643:
1644: // regenerate the xml, now with file path set
1645: doc = Xml.createDocument();
1646: edit.toXml(doc, new Stack());
1647: xml = Xml.writeDocumentToString(doc);
1648:
1649: // update the record
1650: sql = "update CONTENT_RESOURCE set FILE_PATH = ?, XML = ? where RESOURCE_ID = ?";
1651: fields = new Object[3];
1652: fields[0] = edit.m_filePath;
1653: fields[1] = xml;
1654: fields[2] = id;
1655: m_sqlService.dbWrite(connection, sql, fields);
1656:
1657: // m_logger.info(" ** converted: " + id + " size: " +
1658: // edit.m_contentLength);
1659: count.value++;
1660: if ((count.value % 1000) == 0) {
1661: connection.commit();
1662: M_log.info(" ** converted: " + count.value);
1663: }
1664:
1665: return null;
1666: } catch (Throwable e) {
1667: M_log.info(" ** exception converting : " + id
1668: + " : ", e);
1669: return null;
1670: }
1671: }
1672: });
1673:
1674: connection.commit();
1675:
1676: M_log.info("convertToFile: converted resources: "
1677: + count.value);
1678:
1679: m_sqlService.returnConnection(sourceConnection);
1680:
1681: connection.setAutoCommit(wasCommit);
1682: m_sqlService.returnConnection(connection);
1683: } catch (Throwable t) {
1684: M_log.warn("convertToFile: failed: " + t);
1685: }
1686:
1687: M_log.info("convertToFile: done");
1688: }
1689:
1690: /**
1691: * <p>
1692: * Counter is is a counter that can be marked final.
1693: * </p>
1694: */
1695: public class Counter {
1696: public int value = 0;
1697: }
1698:
1699: public Collection getLocks(String id) {
1700: return m_lockManager.getLocks(id);
1701: }
1702:
1703: public void lockObject(String id, String lockId, String subject,
1704: boolean system) {
1705: if (M_log.isDebugEnabled())
1706: M_log.debug("lockObject has been called on: " + id);
1707: try {
1708: m_lockManager.lockObject(id, lockId, subject, system);
1709: } catch (Exception e) {
1710: M_log.warn("lockObject failed: " + e);
1711: e.printStackTrace();
1712: return;
1713: }
1714: if (M_log.isDebugEnabled())
1715: M_log.debug("lockObject succeeded");
1716: }
1717:
1718: public void removeLock(String id, String lockId) {
1719: m_lockManager.removeLock(id, lockId);
1720: }
1721:
1722: public boolean isLocked(String id) {
1723: return m_lockManager.isLocked(id);
1724: }
1725:
1726: public boolean containsLockedNode(String id) {
1727: throw new RuntimeException(
1728: "containsLockedNode has not been implemented");
1729: }
1730:
1731: public void removeAllLocks(String id) {
1732: m_lockManager.removeAllLocks(id);
1733: }
1734:
1735: protected List getFlatResources(String parentId) {
1736: return m_storage.getFlatResources(parentId);
1737: }
1738:
1739: public ContentHostingHandlerResolverImpl getContentHostingHandlerResolver() {
1740: return contentHostingHandlerResolver;
1741: }
1742:
1743: public void setContentHostingHandlerResolver(
1744: ContentHostingHandlerResolverImpl contentHostingHandlerResolver) {
1745: this.contentHostingHandlerResolver = contentHostingHandlerResolver;
1746: }
1747:
1748: }
|