0001: /* ====================================================================
0002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
0003: *
0004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * 3. The end-user documentation included with the redistribution,
0019: * if any, must include the following acknowledgment:
0020: * "This product includes software developed by Jcorporate Ltd.
0021: * (http://www.jcorporate.com/)."
0022: * Alternately, this acknowledgment may appear in the software itself,
0023: * if and wherever such third-party acknowledgments normally appear.
0024: *
0025: * 4. "Jcorporate" and product names such as "Expresso" must
0026: * not be used to endorse or promote products derived from this
0027: * software without prior written permission. For written permission,
0028: * please contact info@jcorporate.com.
0029: *
0030: * 5. Products derived from this software may not be called "Expresso",
0031: * or other Jcorporate product names; nor may "Expresso" or other
0032: * Jcorporate product names appear in their name, without prior
0033: * written permission of Jcorporate Ltd.
0034: *
0035: * 6. No product derived from this software may compete in the same
0036: * market space, i.e. framework, without prior written permission
0037: * of Jcorporate Ltd. For written permission, please contact
0038: * partners@jcorporate.com.
0039: *
0040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
0044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
0046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0051: * SUCH DAMAGE.
0052: * ====================================================================
0053: *
0054: * This software consists of voluntary contributions made by many
0055: * individuals on behalf of the Jcorporate Ltd. Contributions back
0056: * to the project(s) are encouraged when you make modifications.
0057: * Please send them to support@jcorporate.com. For more information
0058: * on Jcorporate Ltd. and its products, please see
0059: * <http://www.jcorporate.com/>.
0060: *
0061: * Portions of this software are based upon other open source
0062: * products and are subject to their respective licenses.
0063: */
0064:
0065: package com.jcorporate.expresso.core.dbobj;
0066:
0067: import com.jcorporate.expresso.core.controller.Controller;
0068: import com.jcorporate.expresso.core.controller.ControllerException;
0069: import com.jcorporate.expresso.core.db.DBException;
0070: import com.jcorporate.expresso.core.i18n.Messages;
0071: import com.jcorporate.expresso.core.job.Job;
0072: import com.jcorporate.expresso.core.misc.ConfigContext;
0073: import com.jcorporate.expresso.core.misc.ConfigManager;
0074: import com.jcorporate.expresso.core.misc.ConfigSetupDefault;
0075: import com.jcorporate.expresso.core.misc.StringUtil;
0076: import com.jcorporate.expresso.core.servlet.StdServlet;
0077: import com.jcorporate.expresso.ext.report.ExpressoReport;
0078: import com.jcorporate.expresso.kernel.ComponentLifecycle;
0079: import com.jcorporate.expresso.kernel.Configuration;
0080: import com.jcorporate.expresso.kernel.ContainerComponentBase;
0081: import com.jcorporate.expresso.kernel.InstallLog;
0082: import com.jcorporate.expresso.kernel.exception.ConfigurationException;
0083: import com.jcorporate.expresso.kernel.management.ExpressoRuntimeMap;
0084: import com.jcorporate.expresso.kernel.util.ClassLocator;
0085: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
0086: import com.jcorporate.expresso.services.controller.RegistrationFactory;
0087: import com.jcorporate.expresso.services.dbobj.Setup;
0088: import org.apache.log4j.Logger;
0089:
0090: import java.net.URL;
0091: import java.util.Collections;
0092: import java.util.Enumeration;
0093: import java.util.HashMap;
0094: import java.util.Hashtable;
0095: import java.util.Iterator;
0096: import java.util.Map;
0097: import java.util.StringTokenizer;
0098: import java.util.Vector;
0099:
0100: /**
0101: * <p/>
0102: * A Schema contains a collection of DBObjects, Controllers, Jobs, and MessageBundles
0103: * allowing them to be created all at once,
0104: * dropped at once, and reported on as a group
0105: * A schema also contains (optional) a list of ReportPage objects
0106: * that make up the standard reports for a package
0107: * </p>
0108: * <p>You create your own schema as the hub of your Expresso-based component.
0109: * To do this, derive your own class from Schema, override the abstract members
0110: * to give your component a name, component code, etc. And then in the constructor
0111: * of the schema, you add the various components such as DBOBjects to your schema.
0112: * </p>
0113: *
0114: * @author Michael Nash
0115: */
0116: public abstract class Schema extends ContainerComponentBase implements
0117: ComponentLifecycle, RegistrationFactory {
0118:
0119: private static Logger log = Logger.getLogger(Schema.class);
0120:
0121: private static Map schemaDefinitions = Collections
0122: .synchronizedMap(new HashMap(5));
0123:
0124: /**
0125: * These are the current setup values for this schema.
0126: */
0127: private Map setupValue = new HashMap();
0128:
0129: /**
0130: * This are setup values that are defined as default values.
0131: */
0132: private Map defaultSetupValues = new HashMap();
0133:
0134: /**
0135: * dbKey is used to indicate that this schema is actually being applied to
0136: * other than the default database. Null indicates it's being applied to the
0137: * default
0138: * database
0139: */
0140: private String dbKey = "";
0141:
0142: /**
0143: * Return the component code, or the directory under the 'expresso' directory
0144: * that the component is set into.
0145: */
0146: private String defaultComponentCode = "";
0147:
0148: /**
0149: * Retrieve a default description of the schema.
0150: */
0151: private String defaultDescription = "No Description Provided";
0152:
0153: /**
0154: * Used to store an instance of this Schema class to prevent a new instance
0155: * being instantiated for access to the messages bundle
0156: */
0157: private static Schema myInstance = null;
0158:
0159: /**
0160: * The path to the message Bundle
0161: */
0162: private String messageBundlePath = "";
0163: private int mUserID;
0164:
0165: /**
0166: * Constructor
0167: */
0168: public Schema() {
0169:
0170: //
0171: //Put per-instance initializations before this line.
0172: //
0173: if (schemaDefinitions.containsKey(this .getClass().getName())) {
0174: //Data already initialized
0175: return;
0176: }
0177:
0178: if (myInstance == null) {
0179: myInstance = this ;
0180: }
0181:
0182: schemaDefinitions.put(this .getClass().getName(),
0183: new SchemaDefinition());
0184:
0185: } /* Schema() */
0186:
0187: /**
0188: * Method to add a dbobject to the list of dbobjects in this schema
0189: *
0190: * @param dbobjectClass the class name of the DBObject that you want to add.
0191: */
0192: protected synchronized void addDBObject(String dbobjectClass) {
0193: addDBObject(dbobjectClass, null, "default");
0194: } /* addDBObject(String) */
0195:
0196: /**
0197: * New method of adding a dbobject to the specified category. Call by
0198: * writing:
0199: *
0200: * @param c the class name of the DBObject that you want to add.
0201: * @param categoryName the category to which this controller belongs.
0202: */
0203: protected synchronized void addDBObject(Class c, String categoryName) {
0204: addDBObject(c.getName(), null, categoryName);
0205: }
0206:
0207: /**
0208: * New method of adding a dbobject to the default category. Call by
0209: * writing:
0210: * <code>addController("your.class.here.<b>class</b>");
0211: *
0212: * @param c the class of the controller that you want to add. If you mis-type
0213: * your controller name, the compiler will catch it at compile time.
0214: */
0215: protected synchronized void addDBObject(Class c) {
0216: addDBObject(c.getName(), null, "default");
0217: }
0218:
0219: /**
0220: * Method to add a dbobject to the list of dbobjects in this schema
0221: * for a named dbother location in the default category. Please note that
0222: * otherdb tables are not created on a DBCreate run.
0223: *
0224: * @param dbobjectClass the name of the database object class to use
0225: * @param otherDBName The dbcontext to use for this dataobject.
0226: */
0227: protected synchronized void addDBObject(String dbobjectClass,
0228: String otherDBName) {
0229: addDBObject(dbobjectClass, otherDBName, "default");
0230: }
0231:
0232: /**
0233: * Method to add a dbobject to the list of dbobjects in this schema
0234: * for a named dbother location and named category.
0235: *
0236: * @param dbobjectClass The name of the dbobject to add to the schema.
0237: * @param otherDBName The dbcontext to use for this dataobject.
0238: * @param categoryName the navigation category to use for this database object
0239: */
0240: protected synchronized void addDBObject(String dbobjectClass,
0241: String otherDBName, String categoryName) {
0242: StringUtil.assertNotBlank(dbobjectClass,
0243: "DB Object class name may not "
0244: + " be null or blank here");
0245: SchemaDefinition sd = getDef();
0246: sd.addMember(dbobjectClass);
0247:
0248: if (otherDBName != null) {
0249: sd.addDBObjectMap(dbobjectClass, otherDBName);
0250: }
0251:
0252: } /* addDBObject(String, String, String) */
0253:
0254: /**
0255: * Add a controller to the default category
0256: *
0257: * @param controllerName the String name of the controller to add to the
0258: * schema
0259: */
0260: protected synchronized void addController(String controllerName) {
0261: addController(controllerName, "default");
0262: }
0263:
0264: /**
0265: * New method of adding a controller to the default category. Call by
0266: * writing:
0267: * <code>addController("your.class.here.<b>class</b>");
0268: *
0269: * @param c the class of the controller that you want to add. If you mis-type
0270: * your controller name, the compiler will catch it at compile time.
0271: */
0272: protected synchronized void addController(Class c) {
0273: addController(c.getName());
0274: }
0275:
0276: /**
0277: * New method to add controller objects to the list of controllers
0278: * in this Schema object. We no longer add the object itself (as this
0279: * is not very efficient, to say the least) we only store the *name*
0280: * of the controller.
0281: *
0282: * @param controllerName The class name of the controller object
0283: * @param categoryName The category to which this controller belongs
0284: */
0285: protected synchronized void addController(String controllerName,
0286: String categoryName) {
0287: SchemaDefinition sd = getDef();
0288: sd.addController(controllerName);
0289: } /*addController(String) */
0290:
0291: /**
0292: * New method of adding a controller to the default category. Call by
0293: * writing:
0294: * <code>addController("your.class.here.<b>class</b>");
0295: *
0296: * @param c the class of the controller that you want to add. If you mis-type
0297: * your controller name, the compiler will catch it at compile time.
0298: * @param categoryName the category to which this controller belongs.
0299: */
0300: protected synchronized void addController(Class c,
0301: String categoryName) {
0302: addController(c.getName(), categoryName);
0303: }
0304:
0305: /**
0306: * Add a new report page to the schema.
0307: *
0308: * @param reportClass the class of the report. Usually obtained by typing
0309: * out the class name and adding ".class" at the end. Example:
0310: * <code>com.jcorporate.ext.report.DownloadUsers<b>.class</b></code>
0311: */
0312: public synchronized void addReportPage(Class reportClass) {
0313: addReportPage(reportClass.getName());
0314: }
0315:
0316: /**
0317: * Add a new ReportPage to the default category
0318: *
0319: * @param reportClassName The class name of a "ReportPage" object that is
0320: * part of this schema
0321: */
0322: public synchronized void addReportPage(String reportClassName) {
0323: StringUtil.assertNotBlank(reportClassName,
0324: "Blank report class name not allowed here");
0325: SchemaDefinition sd = getDef();
0326: sd.addReport(reportClassName);
0327: }
0328:
0329: /**
0330: * Add a new Job object to this schema
0331: *
0332: * @param oneJob New job object to add as a member to this
0333: * schema
0334: * @throws DBException If the object cannot be added
0335: * @deprecated See the addJob(Class) method instead since Expresso 5.6
0336: */
0337: public synchronized void add(Job oneJob) throws DBException {
0338: getDef().addJob(oneJob.getClass().getName());
0339: } /* add(Job) */
0340:
0341: /**
0342: * method of adding a job to the specified category. Call by
0343: * writing:
0344: * <code>addController("your.class.here.<b>class</b>");
0345: *
0346: * @param c the class of the controller that you want to add. If you mis-type
0347: * your controller name, the compiler will catch it at compile time.
0348: */
0349: protected synchronized void addJob(Class c) {
0350: getDef().addJob(c.getName());
0351: }
0352:
0353: /**
0354: * New method of adding a servlet to the specified category. Call by
0355: * writing:
0356: * <code>addController("your.class.here.<b>class</b>");
0357: *
0358: * @param c the class of the controller that you want to add. If you mis-type
0359: * your controller name, the compiler will catch it at compile time.
0360: */
0361: protected synchronized void addServlet(Class c) {
0362: getDef().addServlet(c.getName());
0363: }
0364:
0365: /**
0366: * Add a new setup value to this schema
0367: *
0368: * @param schemaClass Class name of this schema
0369: * @param setupCode Code of the new setup value
0370: * @param descrip A description of the new setup value
0371: * @param defaultValue A default value for the new setup value
0372: * @throws DBException If the value cannot be added to the setup table
0373: * @see #addSetup
0374: * @deprecated since 3/04; use addSetup() instead
0375: */
0376: public synchronized void add(String schemaClass, String setupCode,
0377: String descrip, String defaultValue) throws DBException {
0378: addSetup(schemaClass, setupCode, descrip, defaultValue);
0379: }
0380:
0381: /**
0382: * Add a new setup value to the named schema; will not change value if one already exists in Setup table
0383: *
0384: * @param schemaClass Class name of this schema
0385: * @param setupCode Code of the new setup value
0386: * @param descrip A description of the new setup value
0387: * @param defaultValue A default value for the new setup value
0388: * @throws DBException If the value cannot be added to the setup table
0389: */
0390: public synchronized void addSetup(String schemaClass,
0391: String setupCode, String descrip, String defaultValue)
0392: throws DBException {
0393:
0394: FastStringBuffer fsb = FastStringBuffer.getInstance();
0395: try {
0396: fsb.append(schemaClass);
0397: fsb.append("|");
0398: fsb.append(setupCode);
0399: fsb.append("|");
0400: fsb.append(descrip);
0401: fsb.append("|");
0402: fsb.append(defaultValue);
0403:
0404: getDef().addConfigValue(fsb.toString());
0405: } finally {
0406: fsb.release();
0407: }
0408:
0409: this .defaultSetupValues.put(setupCode, defaultValue);
0410:
0411: }
0412:
0413: /**
0414: * Add a new setup value to this schema for THIS schema; will not change value if one already exists in Setup table
0415: *
0416: * @param setupCode Code of the new setup value
0417: * @param descrip A description of the new setup value
0418: * @param defaultValue A default value for the new setup value
0419: * @throws DBException If the value cannot be added to the setup table
0420: */
0421: public synchronized void addSetup(String setupCode, String descrip,
0422: String defaultValue) throws DBException {
0423: addSetup(getClass().getName(), setupCode, descrip, defaultValue);
0424: }
0425:
0426: /**
0427: * Return the list of configuration values required by this schema
0428: *
0429: * @return Vector A vector of setup/configuration values for this schema
0430: */
0431: public synchronized Vector getConfig() {
0432: Vector newConfig = new Vector();
0433: String oneHolder = null;
0434:
0435: for (Iterator e = getDef().getConfigValues(); e.hasNext();) {
0436: oneHolder = (String) e.next();
0437:
0438: StringTokenizer stk = new StringTokenizer(oneHolder, "|");
0439:
0440: try {
0441: Setup oneSetup = new Setup(
0442: SecuredDBObject.SYSTEM_ACCOUNT);
0443: oneSetup.setField("SchemaClass", stk.nextToken());
0444: oneSetup.setField("SetupCode", stk.nextToken());
0445: oneSetup.setField("Descrip", stk.nextToken());
0446:
0447: //Setup value for many places is blank.
0448: if (stk.hasMoreTokens()) {
0449: oneSetup.setField("SetupValue", stk.nextToken());
0450: }
0451:
0452: newConfig.addElement(oneSetup);
0453: } catch (Exception ee) {
0454: log
0455: .error("Error parsing setup value: "
0456: + oneHolder, ee);
0457: }
0458: } /* for */
0459:
0460: return newConfig;
0461: } /* getConfig() */
0462:
0463: /**
0464: * Return a list of the Controller objects that are members of this
0465: * schema. Controllers are instantiated if not already cached. However, since ControllerFactory caches
0466: * the instances, performance of calls after the initial call is faster
0467: *
0468: * @return java.util.List of Controller objects that belong to this schema
0469: */
0470: public java.util.List getControllerList() {
0471: java.util.List theControllers = new java.util.ArrayList(4);
0472: String oneControllerName = null;
0473: Controller oneController = null;
0474:
0475: for (Iterator ee = getDef().getControllers(); ee.hasNext();) {
0476: oneControllerName = (String) ee.next();
0477:
0478: try {
0479: oneController = ConfigManager.getControllerFactory()
0480: .getController(oneControllerName);
0481: theControllers.add(oneController);
0482: } catch (Exception e) {
0483: log.error("Unable to instantiate controller '"
0484: + oneControllerName + "'", e);
0485: }
0486: } /* for each controller listed */
0487:
0488: return theControllers;
0489:
0490: }
0491:
0492: /**
0493: * Returns the default component code for this schema. Useful for automated
0494: * component testing/installation
0495: *
0496: * @return the component code string as defined by the derived schema class
0497: */
0498: public String getDefaultComponentCode() {
0499: return this .defaultComponentCode;
0500: }
0501:
0502: /**
0503: * Returns the default description for this schema. Useful for automated
0504: * component testing/installation
0505: *
0506: * @return the component friendly name as defined by the derived schema class
0507: */
0508: public String getDefaultDescription() {
0509: return this .defaultDescription;
0510: }
0511:
0512: /**
0513: * Return the name of the context/database connection that this schema is being
0514: * applied to. If none is set, then we are applying to the "default"
0515: * database/context.
0516: *
0517: * @return the database context that this Schema object is associated with.
0518: * @deprecated Use getDataContext() instead. Since v.5.5
0519: */
0520: public synchronized String getDBName() {
0521: if (StringUtil.notNull(dbKey).equals("")) {
0522: return "default";
0523: }
0524:
0525: return dbKey;
0526: } /* getDBName() */
0527:
0528: /**
0529: * Return the name of the context/database connection
0530: * that this schema is being
0531: * applied to. If none is set, then we are applying to the "default"
0532: * database/context.
0533: *
0534: * @return the database context that this Schema object
0535: * is associated with.
0536: * @since Expresso 5.6
0537: */
0538: public synchronized String getDataContext() {
0539: if (StringUtil.notNull(dbKey).equals("")) {
0540: return "default";
0541: }
0542:
0543: return dbKey;
0544: } /* getDBName() */
0545:
0546: /**
0547: * @return an an instance of this schema instance.
0548: */
0549: public static Schema getInstance() {
0550: return myInstance;
0551: } /* getInstance() */
0552:
0553: /**
0554: * Return an enumeration of the jobs that are members of this schema
0555: *
0556: * @return Enumeration List of Transaction objects that belong to
0557: * this schema
0558: */
0559: public Enumeration getJobs() {
0560: Vector theJobs = new Vector();
0561: String oneJobName = null;
0562:
0563: for (Iterator ee = getDef().getJobs(); ee.hasNext();) {
0564: oneJobName = (String) ee.next();
0565:
0566: try {
0567: Class clazz = ClassLocator.loadClass(oneJobName);
0568: Job oneJob = (Job) clazz.newInstance();
0569: theJobs.addElement(oneJob);
0570: } catch (Exception e) {
0571: log.error("Unable to instantiate job '" + oneJobName
0572: + "' belonging to schema '"
0573: + getClass().getName() + "'", e);
0574: }
0575: } /* for each job listed */
0576:
0577: return theJobs.elements();
0578: } /* getJobs() */
0579:
0580: /**
0581: * Return an enumeration of the database objects that belong to this schema
0582: *
0583: * @return Enumeration List of DBObject objects that belong to this schema
0584: */
0585: public Enumeration getMembers() {
0586: Vector theDBObjects = new Vector();
0587: String oneDBObjectName = null;
0588: DBObject oneDBObject = null;
0589:
0590: boolean threadLoader = false;
0591:
0592: if (this .getClass().getClassLoader() != null) {
0593: threadLoader = true;
0594: }
0595:
0596: for (Iterator ee = getDef().getMembers(); ee.hasNext();) {
0597: oneDBObjectName = (String) ee.next();
0598:
0599: try {
0600: oneDBObject = null;
0601: Class clazz = null;
0602: if (threadLoader == true) {
0603: clazz = this .getClass().getClassLoader().loadClass(
0604: oneDBObjectName);
0605: } else {
0606: clazz = ClassLocator.loadClass(oneDBObjectName);
0607: }
0608: oneDBObject = (DBObject) clazz.newInstance();
0609: } catch (Exception e) {
0610: log.error("Unable to instantiate dbobject '"
0611: + oneDBObjectName + "'", e);
0612: }
0613:
0614: if (oneDBObject != null) {
0615:
0616: if (getDataContext() != null) {
0617: try {
0618: oneDBObject.setDBName(getDataContext());
0619: } catch (DBException e) {
0620: log.error("cannot set data context: ", e);
0621: }
0622: }
0623:
0624: // we are creating an object from a no-arg constuctor, without even
0625: // knowing another dbobject which has context. we have the DBName, above,
0626: // but for SecuredDBObjects, we need the requesting UID. Since dealing
0627: // with a schema is a privileged procedure, we have little choice but
0628: // to assume superuser privileges unless we have other information.
0629: // NB: we are actually concerned with RowSecuredDBObject because the default
0630: // constructor for SecuredDBObject already assumes superuser privileges,
0631: // while the default constructor for RowSecuredDBObject does the opposite,
0632: // (more securely) assuming that without any other information, we give
0633: // NO permissions. Anyway, creating the schema is one of the first
0634: // behaviors of an application, so we have to make some assumptions here.
0635:
0636: if (oneDBObject instanceof SecuredDBObject) {
0637: if (getRequestingUser() != 0) {
0638: ((SecuredDBObject) oneDBObject)
0639: .setRequestingUid(getRequestingUser());
0640: } else {
0641: ((SecuredDBObject) oneDBObject)
0642: .setRequestingUid(SecuredDBObject.SYSTEM_ACCOUNT);
0643: }
0644: }
0645:
0646: theDBObjects.addElement(oneDBObject);
0647: } // we created oneDBObject
0648: } /* for each dbobject listed */
0649:
0650: return theDBObjects.elements();
0651: } /* getMembers() */
0652:
0653: /**
0654: * Return the path, relative to the classpath, of the MessageBundle file for
0655: * this schema. For example, the Expresso schema
0656: * (com.jcorporate.expresso.core.ExpressoSchema) returns
0657: * "com/jcorporate/expresso/core", as this is where it's message files are
0658: * stored.
0659: *
0660: * @return A String describing the location of the MessageBundle Path
0661: */
0662: public String getMessageBundlePath() {
0663: return this .messageBundlePath;
0664: }
0665:
0666: /**
0667: * Return the list of ExpressoReport objects that are required by this schema.
0668: *
0669: * @return Vector A list of <code>ExpressoReport</code> objects that are standard reports
0670: * in this schema.
0671: */
0672: public synchronized Vector getReports() {
0673: Vector theReports = new Vector();
0674: String oneReportName = null;
0675: ExpressoReport oneReport = null;
0676:
0677: for (Iterator ee = getDef().getReports(); ee.hasNext();) {
0678: oneReportName = (String) ee.next();
0679:
0680: try {
0681: Class clazz = ClassLocator.loadClass(oneReportName);
0682: oneReport = (ExpressoReport) clazz.newInstance();
0683: } catch (Exception e) {
0684: log.error("Unable to instantiate Expresso Report '"
0685: + oneReportName + "'", e);
0686: }
0687:
0688: theReports.addElement(oneReport);
0689: } /* for each servlet listed */
0690:
0691: return theReports;
0692: } /* getReports() */
0693:
0694: /**
0695: * Return an enumeration of the servlets that are members of this schema
0696: *
0697: * @return Enumeration List of StdServlet objects that belong to
0698: * this schema
0699: */
0700: public Enumeration getServlets() {
0701: Vector theServlets = new Vector();
0702: String oneServletName = null;
0703: StdServlet oneServlet = null;
0704:
0705: for (Iterator ee = getDef().getServlets(); ee.hasNext();) {
0706: oneServletName = (String) ee.next();
0707:
0708: try {
0709: Class clazz = ClassLocator.loadClass(oneServletName);
0710: oneServlet = (StdServlet) clazz.newInstance();
0711: theServlets.addElement(oneServlet);
0712: } catch (Exception e) {
0713: log.error("Unable to instantiate servlet '"
0714: + oneServletName + "'", e);
0715: }
0716: } /* for each servlet listed */
0717:
0718: return theServlets.elements();
0719: } /* getServlets() */
0720:
0721: /**
0722: * Return the value if this property is defined in the properties file for
0723: * this config key.
0724: *
0725: * @param paramName Property Name
0726: * @param defaultValue value if property is not defined
0727: * @return String Value of this property in the property file for this DB
0728: * config.
0729: */
0730: protected String getSetupDefault(String paramName,
0731: String defaultValue) {
0732: try {
0733: ConfigContext myContext = ConfigManager
0734: .getContext(getDataContext());
0735: ConfigSetupDefault oneValue = null;
0736:
0737: for (Enumeration sv = myContext.getSetupDefaults()
0738: .elements(); sv.hasMoreElements();) {
0739: oneValue = (ConfigSetupDefault) sv.nextElement();
0740:
0741: if (oneValue.getName().equals(paramName)) {
0742: return oneValue.getValue();
0743: }
0744: }
0745: } catch (com.jcorporate.expresso.core.misc.ConfigurationException ce) {
0746: log.error(ce);
0747: }
0748:
0749: return defaultValue;
0750: } /* getSetupDefault(String, String) */
0751:
0752: /**
0753: * Return a single transaction as the "starting point" for this application.
0754: * Each Schema object may define such a transaction, and the appropriate
0755: * application can then be invoked from that point
0756: *
0757: * @return a Controller Instance of the starting controller point.
0758: */
0759: public Controller getStartController() {
0760: return null;
0761: } /* getStartController() */
0762:
0763: /**
0764: * Retrieve one of the Setup values for the schema.
0765: *
0766: * @param key The setup value key
0767: * @return java.lang.String the value of the setup value. May be null;
0768: */
0769: public String getSetupValue(String key) {
0770: return (String) setupValue.get(key);
0771: }
0772:
0773: /**
0774: * Sets the setup values for the given key
0775: *
0776: * @param key The name of the setup value.
0777: * @param value the Value of the setup value.
0778: */
0779: public void setSetupValue(String key, String value) {
0780: setupValue.put(key, value);
0781: }
0782:
0783: /**
0784: * preferable way of performaing other setup. Utilizes the context independant
0785: * logging system.
0786: *
0787: * @param installLog the InstallLog implementation that the setup process
0788: * will log progress to.
0789: * @param dataContext he database context to execute this process against.
0790: * @throws DBException If there's a database communication error
0791: */
0792: public synchronized void otherSetup(InstallLog installLog,
0793: String dataContext) throws DBException {
0794: }
0795:
0796: /**
0797: * Perform any additional setup/intialize functions required
0798: * by this schema. This is where applications can set up default
0799: * values for lookup tables, reference values, etc.
0800: * Subclass does not extend this method if it is not needed.
0801: *
0802: * @param dbName The database context to execute this process against.
0803: * @throws DBException If there's a database communication error
0804: * @deprecated 5.5+; 10/04. use otherSetup(log, dbcontext) instead
0805: */
0806: public synchronized void otherSetup(String dbName)
0807: throws DBException {
0808:
0809: } /* otherSetup(String) */
0810:
0811: /**
0812: * Set the database name/context for this schema. If setDBName is not called,
0813: * the "default" db name and context is used.
0814: *
0815: * @param newOther The name of the context or database to use
0816: * @throws DBException If there's a problem switching to the database context.
0817: * @deprecated Since Expresso 5.6 Use setDataContext(String) instead.
0818: */
0819: public synchronized void setDBName(String newOther)
0820: throws DBException {
0821: setDataContext(newOther);
0822: } /* setDBName(String) */
0823:
0824: /**
0825: * Set the database name/context for this schema. If setDBName is not called,
0826: * the "default" db name and context is used.
0827: *
0828: * @param newOther The name of the context or database to use
0829: * @throws DBException If there's a problem switching to the database context.
0830: */
0831: public synchronized void setDataContext(String newOther)
0832: throws DBException {
0833: dbKey = newOther;
0834: }
0835:
0836: /**
0837: * Go through each DBobject in the schema and call populateDefaultValues.<p>
0838: * See: @see com.jcorporate.expresso.core.dbobj.DBObject.populateDefaultValues
0839: *
0840: * @param dbName The name of the database to set this up on.
0841: */
0842: public synchronized void setupDefaultValues(String dbName) {
0843: try {
0844: setupDefaultValuesWithException(dbName);
0845: } catch (DBException de) {
0846: log.error("Unable to populate table with default values",
0847: de);
0848: }
0849: } /* setupDefaultValues(String) */
0850:
0851: /**
0852: * Go through each DBobject and each Controller in the schema and call default-populate methods.<p>
0853: * See: @see com.jcorporate.expresso.core.dbobj.DBObject.populateDefaultValues
0854: * See: @see com.jcorporate.expresso.core.controller.Controller.setupDefaultValues
0855: *
0856: * @param dbName The name of the database to set this up on.
0857: * @throws DBException if a database exception occurs
0858: */
0859: public synchronized void setupDefaultValuesWithException(
0860: String dbName) throws DBException {
0861:
0862: if (ExpressoRuntimeMap.getDefaultRuntime() != null) {
0863: log
0864: .warn("Setup Values no longer apply in the Expresso Runtime context."
0865: + " please add them to your Metadata for various values instead");
0866: }
0867:
0868: DBObject oneMember = null;
0869:
0870: for (Enumeration e = getMembers(); e.hasMoreElements();) {
0871: oneMember = (DBObject) e.nextElement();
0872: if (log.isInfoEnabled()) {
0873: log.info("Populating table "
0874: + oneMember.getDataContext());
0875: }
0876: oneMember.setDataContext(dbName);
0877: oneMember.populateDefaultValues();
0878: }
0879:
0880: Controller oneController = null;
0881:
0882: for (Iterator e = this .getControllerList().iterator(); e
0883: .hasNext();) {
0884: oneController = (Controller) e.next();
0885: if (log.isInfoEnabled()) {
0886: log.info("Populating Default Controller Data "
0887: + oneController.getClass().getName());
0888: }
0889: oneController.setupDefaultValues(dbName);
0890: }
0891:
0892: populateSchemaData(dbName);
0893: } /* setupDefaultValues(String) */
0894:
0895: /**
0896: * Allow populations of sample data where all tables must be set up first.
0897: *
0898: * @param dbName The name to add the data to
0899: * see com.jcorporate.eforum.ForumSchema#populateSchemaData for example.
0900: * @throws DBException if an error occurs while populating the table.
0901: */
0902: public synchronized void populateSchemaData(String dbName)
0903: throws DBException {
0904: }
0905:
0906: /**
0907: * Return the list of Junit tests in this application
0908: *
0909: * @return An Enumeration of all tests for this schema
0910: * @deprecated Since Expresso 5.6 Tests have been separated from
0911: * the main code base.
0912: */
0913: public Enumeration getTests() {
0914: Vector v = new Vector();
0915: for (Iterator i = getDef().getTests(); i.hasNext();) {
0916: v.add(i.next());
0917: }
0918: return v.elements();
0919: } /* getTests() */
0920:
0921: /**
0922: * Utility function to get the SchemaDefinitions
0923: *
0924: * @return the SchemaDefinition class associated with this schema type.
0925: */
0926: private SchemaDefinition getDef() {
0927: return (SchemaDefinition) schemaDefinitions.get(this .getClass()
0928: .getName());
0929: }
0930:
0931: /**
0932: * Retrieves the DBObject Map for table creation.
0933: *
0934: * @return java.util.Hashtable
0935: */
0936: public Hashtable getDBObjMap() {
0937: return getDef().getDbobjMap();
0938: }
0939:
0940: /**
0941: * Get the i18N'ized string for this schema
0942: *
0943: * @param stringCode The string code to find in the messages bundle.
0944: * @return The Mapped String
0945: */
0946: protected String getString(String stringCode) {
0947: Object[] args = {};
0948: String language = null;
0949: String country = null;
0950:
0951: try {
0952: ConfigContext myContext = ConfigManager
0953: .getContext(getDataContext());
0954: language = myContext.getLanguage();
0955: country = myContext.getCountry();
0956: } catch (com.jcorporate.expresso.core.misc.ConfigurationException ce) {
0957: language = "en";
0958: country = "US";
0959: }
0960:
0961: return Messages.getStringByPath(getMessageBundlePath(),
0962: language, country, stringCode, args);
0963: } /* getString(String) */
0964:
0965: /**
0966: * <p>Method to return the current version number of an application Schema.
0967: * Individual Schema objects may override this method if they define a version,
0968: * then other dependant applications can use that information to make sure
0969: * that the current version dependancies are met.</p>
0970: * <p>How to define your own version string:</p>
0971: * <p>The format is: MajorVersion.MinorVersion.Release-EA Release Number<p>
0972: * <p>MajorVerseion,MinorVersion, and Release represent the typical: 1.0.1
0973: * type of version formatting. -EAReleaseNumber is also a number but is optional
0974: * if you do not wish to use a EA number if the version number.</p>
0975: * <p><b>Examples</b><p>
0976: * <ul>
0977: * <li>1.0.1 : First Major Version with a bugfix release.</li>
0978: * <li>2.2.2-2: Second Major Version, Second Minor Version, Second Bugfix release
0979: * and it is currently considered ea-2</li>
0980: * </ul>
0981: *
0982: * @return the Version you define for your system.
0983: */
0984: public String getVersion() {
0985: if (this .getMetaData() != null) {
0986: return this .getMetaData().getVersionNumber();
0987: } else {
0988: return "No Version Defined";
0989: }
0990: }
0991:
0992: /**
0993: * Method for a schema to define a dependance on another schema
0994: * with a particular version - e.g. if eContent requires
0995: * expresso 3.11, it can call this method to ensure that's the version it's
0996: * being run with
0997: *
0998: * @param versionString String the string version this requires.
0999: * @param schemaClassName the class name to check against.
1000: * @throws DBException if an error occurs locating the appropriate schema
1001: * class
1002: */
1003: protected void requiresVersion(String versionString,
1004: String schemaClassName) throws DBException {
1005: Schema otherSchema = instantiate(schemaClassName);
1006:
1007: if (otherSchema.getVersion().equals(versionString)) {
1008: return;
1009: }
1010: /* If the two versions are convertable to numbers, see if the */
1011: /* available version is greater than the required version - */
1012: /* if so, just log a warning */
1013: try {
1014: String foundVersionString = otherSchema.getVersion();
1015: String requiredVersionString = versionString;
1016:
1017: StringTokenizer stok1 = new StringTokenizer(
1018: foundVersionString, ".");
1019: StringTokenizer stok2 = new StringTokenizer(
1020: requiredVersionString, ".");
1021:
1022: if (stok1.hasMoreTokens() && stok2.hasMoreTokens()) {
1023: int foundVersionNumbers[] = { 0, 0, 0, 0 };
1024: int requiredVersionNumbers[] = { 0, 0, 0, 0 };
1025: try {
1026: parseVersionString(stok1, foundVersionNumbers);
1027: parseVersionString(stok2, requiredVersionNumbers);
1028:
1029: if (foundVersionNumbers[0] == requiredVersionNumbers[0]) {
1030: if (foundVersionNumbers[1] == requiredVersionNumbers[1]) {
1031: if (foundVersionNumbers[2] > requiredVersionNumbers[2]) {
1032: return;
1033: } else {
1034: if (log.isInfoEnabled()) {
1035: log
1036: .info("Schema '"
1037: + getClass()
1038: .getName()
1039: + "', version "
1040: + getVersion()
1041: + " requires version "
1042: + versionString
1043: + " of schema '"
1044: + schemaClassName
1045: + "', but version "
1046: + otherSchema
1047: .getVersion()
1048: + " was found instead. You might encounter "
1049: + "some problems because of bugs being fixed. "
1050: + "It is recommended that you upgrade to the required version");
1051: }
1052: return;
1053:
1054: }
1055:
1056: } else {
1057: log
1058: .warn("Schema '"
1059: + getClass().getName()
1060: + "', version "
1061: + getVersion()
1062: + " requires version "
1063: + versionString
1064: + " of schema '"
1065: + schemaClassName
1066: + "', but version "
1067: + otherSchema.getVersion()
1068: + " was found instead. You may encounter "
1069: + "some problems because of the minor version differences.");
1070: return;
1071: }
1072:
1073: } else {
1074: log
1075: .error("Schema '"
1076: + getClass().getName()
1077: + "', version "
1078: + getVersion()
1079: + " requires version "
1080: + versionString
1081: + " of schema '"
1082: + schemaClassName
1083: + "', but version "
1084: + otherSchema.getVersion()
1085: + " was found instead. You may encounter "
1086: + "serious problems because of the major version differences.");
1087: return;
1088: }
1089: } catch (NumberFormatException ex) {
1090: log.error("Schema '" + getClass().getName()
1091: + "', version " + getVersion()
1092: + " requires version " + versionString
1093: + " of schema '" + schemaClassName
1094: + "', but version "
1095: + otherSchema.getVersion()
1096: + " was found instead.");
1097: return;
1098: }
1099: } else {
1100: if (stok1.hasMoreTokens()) {
1101: log.warn("Unable to find version information for :"
1102: + schemaClassName);
1103: } else {
1104: log.warn("Unable to find version information for :"
1105: + this .getClass().getName());
1106: }
1107:
1108: return;
1109: }
1110: } catch (Exception ne) {
1111: log.warn("Unable to convert version numbers to strings");
1112: }
1113:
1114: log.error("Schema '" + getClass().getName() + "', version "
1115: + getVersion() + " requires version " + versionString
1116: + " of schema '" + schemaClassName + "', but version "
1117: + otherSchema.getVersion() + " was found instead.");
1118: } /* requiresVersion */
1119:
1120: /**
1121: * Used by requiresVersion to parse the version number into an integer array
1122: * that is easy to analyze
1123: *
1124: * @param tokenizer a tokenizer with comma's and parsing the string.
1125: * @param parsedNumbers an array of 4 integers.
1126: * @throws NumberFormatException if there's an error parsing the values.
1127: */
1128: private void parseVersionString(StringTokenizer tokenizer,
1129: int parsedNumbers[]) throws NumberFormatException {
1130: int index = 0;
1131: while (tokenizer.hasMoreTokens()) {
1132: String temp = tokenizer.nextToken();
1133: if (temp.indexOf("-") > 0 && index == 2) {
1134: StringTokenizer releaseTokenizer = new StringTokenizer(
1135: temp, "-");
1136: String buildNum = releaseTokenizer.nextToken();
1137: String eaNum = releaseTokenizer.nextToken();
1138: parsedNumbers[index] = Integer.parseInt(buildNum);
1139: index++;
1140: parsedNumbers[index] = Integer.parseInt(eaNum);
1141: index++;
1142: } else {
1143: parsedNumbers[index] = Integer.parseInt(temp);
1144: }
1145: index++;
1146:
1147: if (index >= 4) {
1148: return;
1149: }
1150: }
1151:
1152: }
1153:
1154: /**
1155: * Convenience method to create a Schema object from it's name
1156: *
1157: * @param className The ClassName to instantiate
1158: * @return A newly initialized Schema Object
1159: * @throws DBException if there's an instantiation problem
1160: */
1161: public static Schema instantiate(String className)
1162: throws DBException {
1163: StringUtil.assertNotBlank(className, "Schema class name "
1164: + " may not be blank or null here");
1165:
1166: try {
1167:
1168: Class c = ClassLocator.loadClass(className);
1169: return (Schema) c.newInstance();
1170: } catch (ClassNotFoundException cn) {
1171: throw new DBException("Schema object '" + className
1172: + "' not found", cn);
1173: } catch (InstantiationException ie) {
1174: throw new DBException("Schema object '" + className
1175: + "' cannot be instantiated", ie);
1176: } catch (IllegalAccessException iae) {
1177: throw new DBException(
1178: "llegal access loading "
1179: + "Schema object '"
1180: + className
1181: + "'. "
1182: + "Your schema must have a default public constructor",
1183: iae);
1184: } catch (java.lang.Throwable t) {
1185: t.printStackTrace();
1186: throw new DBException("Error instantiating schema: "
1187: + className + ".", t);
1188:
1189: }
1190: }
1191:
1192: /**
1193: * Base metadata location. All schemas have the same component metadata,
1194: * unless you want to specify your own. In which case, you'll want to
1195: * override based upon your own information.
1196: *
1197: * @return java.net.URL
1198: */
1199: public URL getMetadataLocation() {
1200: return Schema.class.getResource("Schema.xml");
1201: }
1202:
1203: /**
1204: * Initialize Lifecycle event. Provide quick initialization
1205: */
1206: public void initialize() {
1207: this .dbKey = this .getParent().getMetaData().getName();
1208: }
1209:
1210: /**
1211: * Provide Configurations
1212: *
1213: * @param newConfig the new configuration object
1214: */
1215: public void configure(Configuration newConfig)
1216: throws ConfigurationException {
1217: this .setupValue = newConfig.getMappedProperties("SetupValue");
1218:
1219: //
1220: //We have to merge the saved setup values with these ones.
1221: //
1222: for (Iterator i = this .defaultSetupValues.keySet().iterator(); i
1223: .hasNext();) {
1224: String key = (String) i.next();
1225: if (!setupValue.containsKey(key)) {
1226: setupValue.put(key, defaultSetupValues.get(key));
1227: }
1228: }
1229:
1230: this .defaultComponentCode = (String) newConfig
1231: .get("DefaultComponentCode");
1232: this .defaultDescription = (String) newConfig
1233: .get("DefaultDescription");
1234: this .messageBundlePath = (String) newConfig
1235: .get("MessageBundlePath");
1236: }
1237:
1238: /**
1239: * Reconfigure Lifecycle Event. Nullify values and restart.
1240: *
1241: * @param newConfig The new Configuration
1242: */
1243: public void reconfigure(Configuration newConfig)
1244: throws ConfigurationException {
1245: synchronized (Schema.class) {
1246: this .setupValue = null;
1247: this .defaultComponentCode = null;
1248: this .defaultDescription = null;
1249: this .messageBundlePath = null;
1250: configure(newConfig);
1251: }
1252: }
1253:
1254: public void destroy() {
1255: // schemaDefinitions.remove(this.getClass().getName());
1256: }
1257:
1258: /**
1259: * Retrieve the login controller for your schema. The default implementation
1260: * checks the ClassHandler section and returns it or the default (SimpleLogin)
1261: * if there is none defined in the ClassHandlers. Override for your own apps
1262: * to have custom and multiple logins and registration controllers.
1263: *
1264: * @return Controller Instance
1265: * @throws ControllerException if there is an error instantiating the controller
1266: */
1267: public Controller getLoginController() throws ControllerException {
1268: String className = ConfigManager
1269: .getClassHandler(com.jcorporate.expresso.services.controller.LoginController.CLASS_HANDLER_NAME);
1270: if (className == null || className.length() == 0) {
1271: className = com.jcorporate.expresso.services.controller.LoginController.DEFAULT_CLASS_NAME;
1272: }
1273:
1274: return ConfigManager.getControllerFactory().getController(
1275: className);
1276: }
1277:
1278: /**
1279: * Retrieve the registration controller. The default version checks the
1280: * classhandlers section in the expresso-config.xml file and returns what's
1281: * appropriate there or SimpleRegistration if none is defined.
1282: *
1283: * @return a controller instance for Registration
1284: * @throws ControllerException if there is an error instantiating the controller
1285: */
1286: public Controller getRegistrationController()
1287: throws ControllerException {
1288: String className = ConfigManager
1289: .getClassHandler("registration");
1290: if (className == null || className.length() == 0) {
1291: className = com.jcorporate.expresso.services.controller.SimpleRegistration.class
1292: .getName();
1293: }
1294:
1295: return ConfigManager.getControllerFactory().getController(
1296: className);
1297: } /* instantiate(String) */
1298:
1299: /**
1300: * Set the user ID of requester.
1301: *
1302: * @param uid ID of requesting user
1303: */
1304: public void setRequestingUser(int uid) {
1305: mUserID = uid;
1306: }
1307:
1308: /**
1309: * Retrieve the UID of requesting user.
1310: *
1311: * @return UID of requesting user, if known. otherwise, returns 0
1312: */
1313: public int getRequestingUser() {
1314: return mUserID;
1315: }
1316:
1317: /**
1318: * Checks if a particular dbobject resides in a given schema.
1319: *
1320: * @param dbObject the object to check against.
1321: * @return true if this schema contains this object
1322: */
1323: public boolean contains(DBObject dbObject) {
1324: SchemaDefinition def = getDef();
1325: return def.contains(dbObject);
1326: }
1327:
1328: } /* Schema */
|