0001: /*
0002: * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
0003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
0004: */
0005:
0006: package com.sun.portal.harness;
0007:
0008: import java.io.FileInputStream;
0009: import java.io.FileNotFoundException;
0010:
0011: import java.util.Map;
0012: import java.util.Iterator;
0013: import java.util.List;
0014: import java.util.ArrayList;
0015: import java.util.HashMap;
0016: import java.util.Vector;
0017: import java.util.StringTokenizer;
0018: import java.util.Properties;
0019:
0020: import java.net.URL;
0021: import java.net.MalformedURLException;
0022:
0023: import org.w3c.dom.Document;
0024: import org.w3c.dom.Element;
0025: import org.w3c.dom.Node;
0026: import org.w3c.dom.NodeList;
0027: import org.w3c.dom.Attr;
0028:
0029: import javax.xml.parsers.DocumentBuilder;
0030: import javax.xml.parsers.DocumentBuilderFactory;
0031:
0032: import com.sun.portal.desktop.context.ContextError;
0033:
0034: import com.sun.portal.desktop.deployment.Par;
0035: import com.sun.portal.desktop.deployment.ExtractOp;
0036:
0037: import com.sun.portal.providers.ProviderEditTypes;
0038: import com.sun.portal.providers.ProviderWidths;
0039:
0040: import com.sun.portal.portlet.cli.PDProviderEntryGenerator;
0041: import com.sun.portal.portlet.cli.PDWebAppUpdater;
0042:
0043: import javax.servlet.http.HttpServletRequest;
0044:
0045: // import com.sun.portal.desktop.context.PropertiesContext;
0046: // NOTE - this class COULD be said to implement this interface, but it
0047: // is not public in desktop.context, and we don't need the following methods:
0048: //
0049: // setSelectedChannels
0050: // getHelp
0051: // getClassName
0052: // refresh
0053: // init
0054: // setAvailableChannels
0055: // getAvailableChannels
0056: // addClient
0057: // existsClient
0058:
0059: public class HarnessProperties implements ProviderEditTypes,
0060: ProviderWidths /*, PropertiesContext */{
0061:
0062: public static final int WS_INITIAL_INPUT = 1;
0063: public static final int WS_PROVIDER_RUN = 2;
0064: public static final int WS_TOOL_ADMIN = 3;
0065:
0066: // Public argument strings. Prefixed to avoid conflict with HarnessProvider
0067: // arguments. Prefix isn't public, but has to appear first to avoid forward reference.
0068:
0069: private static final String ARG_PREFIX = "PE_";
0070:
0071: // ARG_LIST_COLL is used with 0-based numeric suffixes for however man components are
0072: // desired. We can infer that we are navigating by the lack of an operation
0073: // No LIST arguments present will simply result in displaying the top of the
0074: // default channels properties. ARG_LIST_VAR is used to encode either a locale
0075: // or a final collection name, based on data value (ARGLVAR_LOC and ARGLVAR_COLL
0076: // prefixes)
0077:
0078: public static final String ARG_LIST_COLL = ARG_PREFIX
0079: + "LIST_COLL_";
0080: public static final String ARG_LIST_LOCALE = ARG_PREFIX
0081: + "LIST_LOCALE";
0082: public static final String ARG_LIST_CHANNEL = ARG_PREFIX
0083: + "CHANNEL";
0084: public static final String ARG_LIST_VAR = ARG_PREFIX + "LIST_VAR";
0085:
0086: public static final String ARG_OPERATION = ARG_PREFIX + "OP";
0087: public static final String ARG_LIST_ITEM = ARG_PREFIX + "LIST_ITEM";
0088: public static final String ARG_CHANGE_VALUE = ARG_PREFIX
0089: + "CHG_VALUE";
0090: public static final String ARG_ADD_NAME = ARG_PREFIX + "ADD_NAME";
0091: public static final String ARG_ADD_VALUE = ARG_PREFIX + "ADD_VALUE";
0092: public static final String ARG_ADDLOC_LANG = ARG_PREFIX
0093: + "ADDLOC_LANG";
0094: public static final String ARG_ADDLOC_COUNTRY = ARG_PREFIX
0095: + "ADDLOC_COUNTRY";
0096: public static final String ARG_ADDLOC_VAR = ARG_PREFIX
0097: + "ADDLOC_VAR";
0098: public static final String ARG_ADD_USELOC = ARG_PREFIX + "USE_LOC";
0099:
0100: public static final String ARGOP_DELETE = "delete";
0101: public static final String ARGOP_CHANGE = "change";
0102: public static final String ARGOP_ADDSTRING = "addstring";
0103: public static final String ARGOP_ADDINTEGER = "addint";
0104: public static final String ARGOP_ADDBOOLEAN = "addbool";
0105: public static final String ARGOP_ADDCOLLECTION = "addcoll";
0106:
0107: //static variables used for processing the portlet.xml file
0108: public static final String APP_NAME = "portlet";
0109: public static final String PORTLET_BUILDER = "portlet_builder";
0110:
0111: //static variables used for creating channel element
0112: public static final String TAG_CHANNEL = "Channel";
0113: public static final String ATR_NAME = "name";
0114: public static final String ATR_PROVIDER = "provider";
0115: public static final String TAG_PROPERTIES = "Properties";
0116: public static final String TAG_STRING = "String";
0117: public static final String ATR_VALUE = "value";
0118:
0119: //static variables for the roles and users mapping file used by
0120: //the portlet deployer code
0121: public static final String ROLES_FILE = "RolesMap.properties";
0122: public static final String USERINFO_FILE = "UserInfoMap.properties";
0123: public static final String PDCONFIG_FILE = "PDConfig.properties";
0124:
0125: public static final char ARGLVAR_LOC = 'L';
0126: public static final char ARGLVAR_COLL = 'C';
0127:
0128: private HarnessProperties() throws ProviderHarnessException {
0129:
0130: // These should be redefined by "init()"
0131:
0132: m_ChannelName = "UNDEFINED CHANNEL";
0133: m_ProviderName = "UNDEFINED PROVIDER";
0134: m_LocaleString = "en_us";
0135:
0136: makeLocsArray();
0137: setPropertyWriteState(WS_INITIAL_INPUT);
0138:
0139: m_OurChannel = null;
0140: m_OtherChannels = new Vector();
0141: m_UserNames = new Vector();
0142: }
0143:
0144: // factory method to avoid having a published exception throwing constructor.
0145:
0146: static HarnessProperties makeHarnessProperties(String user,
0147: String usersfile, String compfile, String portAppDir,
0148: String configdir) throws ProviderHarnessException {
0149: HarnessProperties prop = new HarnessProperties();
0150: prop.init(user, usersfile, compfile, portAppDir, configdir);
0151: return prop;
0152: }
0153:
0154: void processRequest(HttpServletRequest req)
0155: throws ProviderHarnessException {
0156:
0157: m_EditError = null;
0158:
0159: // if an operation is specified, it operates on our current list and
0160: // we return.
0161:
0162: try {
0163: String op = req.getParameter(ARG_OPERATION);
0164: if (op != null) {
0165: setPropertyWriteState(WS_TOOL_ADMIN);
0166: performOperation(op, req);
0167: return;
0168: }
0169:
0170: setEditList(req);
0171: } catch (ContextError ex) {
0172: m_EditError = ex.getMessage();
0173: } finally {
0174: setPropertyWriteState(WS_PROVIDER_RUN);
0175: }
0176: }
0177:
0178: // We have public entry points for our edit interface - otherwise,
0179: // this class is jusrt used within the package.
0180:
0181: public String[] getEditCollectionPath() {
0182: return (String[]) m_EditPath.toArray(new String[m_EditPath
0183: .size()]);
0184: }
0185:
0186: public String[] getEditCollNames() {
0187: return (String[]) m_EditCollNames
0188: .toArray(new String[m_EditCollNames.size()]);
0189: }
0190:
0191: public String getEditChannel() {
0192: return m_EditChannel != null ? m_EditChannel : m_ChannelName;
0193: }
0194:
0195: public String getEditLocale() {
0196: return m_EditLocale;
0197: }
0198:
0199: public String[] getEditLocales() {
0200: return m_EditProps.getLocaleList();
0201: }
0202:
0203: public HashMap getEditAtoms() {
0204: return m_EditAtomicMap;
0205: }
0206:
0207: public String getEditError() {
0208: return m_EditError;
0209: }
0210:
0211: public static String getObjectTypeString(Object obj) {
0212: try {
0213: switch (getObjectType(obj)) {
0214: case TY_COLLECTION:
0215: return "Collection";
0216: case TY_INT:
0217: return "Integer";
0218: case TY_BOOL:
0219: return "Boolean";
0220: case TY_STRING:
0221: return "String";
0222: default:
0223: break;
0224: }
0225: } catch (ContextError err) {
0226: }
0227:
0228: return "Unrecognized";
0229: }
0230:
0231: boolean existsBooleanProperty(String channel, String name) {
0232: return getTable(channel).lookup(name, TY_BOOL, false) != null;
0233: }
0234:
0235: boolean getBooleanProperty(String channel, String key) {
0236: Boolean bobj = (Boolean) getTable(channel).lookup(key, TY_BOOL,
0237: false);
0238: if (bobj == null) {
0239: nullError("boolean", channel, key);
0240: }
0241: return bobj.booleanValue();
0242: }
0243:
0244: Object getProperty(String channel, String key, Object def) {
0245: Object o = getTable(channel).lookup(key, TY_NONE, false);
0246: if (o == null) {
0247: return def;
0248: }
0249: return o;
0250: }
0251:
0252: Map getCollectionProperty(String channel, String key, Map def) {
0253: Map m = (Map) getTable(channel).lookup(key, TY_COLLECTION,
0254: false);
0255: if (m == null) {
0256: return def;
0257: }
0258: return m;
0259: }
0260:
0261: boolean existsCollectionProperty(String channel, String name) {
0262: return getTable(channel).lookup(name, TY_COLLECTION, false) != null;
0263: }
0264:
0265: boolean existsCollectionProperty(String channel, String name,
0266: boolean localized) {
0267: return getTable(channel).lookup(name, TY_COLLECTION, localized) != null;
0268: }
0269:
0270: String getTitle(String channel) {
0271: return getStringProperty(channel, "title", true);
0272: }
0273:
0274: String getDescription(String channel) {
0275: return getTitle(channel);
0276: }
0277:
0278: String getProviderClass() {
0279: return m_ProviderClass;
0280: }
0281:
0282: // NOTE - in the real iPS code, you can set collection properties using
0283: // a list or a map, but they come back only as maps. This is because iPS
0284: // does exactly what we do here - converts the list into a map which maps
0285: // each list item to itself.
0286:
0287: Map setCollectionProperty(String channel, String key, List val) {
0288: Iterator it = val.iterator();
0289: HashMap hm = new HashMap();
0290: while (it.hasNext()) {
0291: Object obj = it.next();
0292: hm.put(obj, obj);
0293: }
0294: return setCollectionProperty(channel, key, hm);
0295: }
0296:
0297: String getStringProperty(String channel, String key) {
0298: String s = (String) getTable(channel).lookup(key, TY_STRING,
0299: false);
0300:
0301: if (s == null) {
0302: nullError("string", channel, key);
0303: }
0304: return s;
0305: }
0306:
0307: String getStringProperty(String channel, String key, String def) {
0308: String s = (String) getTable(channel).lookup(key, TY_STRING,
0309: false);
0310: if (s == null) {
0311: return def;
0312: }
0313: return s;
0314: }
0315:
0316: String getStringProperty(String channel, String key,
0317: boolean localized) {
0318: String s = (String) getTable(channel).lookup(key, TY_STRING,
0319: localized);
0320: if (s == null) {
0321: nullError("string", channel, key);
0322: }
0323: return s;
0324: }
0325:
0326: String getStringProperty(String channel, String key, String def,
0327: boolean localized) {
0328: String s = (String) getTable(channel).lookup(key, TY_STRING,
0329: localized);
0330: if (s == null) {
0331: return def;
0332: }
0333: return s;
0334: }
0335:
0336: int getRefreshTime(String channel) {
0337: return Integer.parseInt(getStringProperty(channel,
0338: "refreshTime"));
0339: }
0340:
0341: boolean getBooleanProperty(String channel, String key, boolean def) {
0342: Boolean bobj = (Boolean) getTable(channel).lookup(key, TY_BOOL,
0343: false);
0344: if (bobj == null) {
0345: return def;
0346: }
0347: return bobj.booleanValue();
0348: }
0349:
0350: int getWidth(String channel) {
0351: String val = getStringProperty(channel, "width");
0352: if (val.equalsIgnoreCase("thin")) {
0353: return WIDTH_THIN;
0354: }
0355: if (val.equalsIgnoreCase("full_top")) {
0356: return WIDTH_FULL_TOP;
0357: }
0358: if (val.equalsIgnoreCase("full_bottom")) {
0359: return WIDTH_FULL_BOTTOM;
0360: }
0361: return WIDTH_THICK;
0362: }
0363:
0364: int getIntegerProperty(String channel, String key, int def) {
0365: Integer iobj = (Integer) getTable(channel).lookup(key, TY_INT,
0366: false);
0367: if (iobj == null) {
0368: return def;
0369: }
0370: return iobj.intValue();
0371: }
0372:
0373: boolean existsStringProperty(String channel, String name,
0374: boolean localized) {
0375: return getTable(channel).lookup(name, TY_STRING, localized) != null;
0376: }
0377:
0378: Object getProperty(String channel, String key) {
0379: Object o = getTable(channel).lookup(key, TY_NONE, false);
0380: if (o == null) {
0381: nullError("object", channel, key);
0382: }
0383: return o;
0384: }
0385:
0386: Map setCollectionProperty(String channel, String key, Map val) {
0387: getTable(channel).enter(key, TY_COLLECTION, val);
0388: return val;
0389: }
0390:
0391: boolean existsStringProperty(String channel, String name) {
0392: return getTable(channel).lookup(name, TY_STRING, false) != null;
0393: }
0394:
0395: String getProviderName(String channel) {
0396: return m_ProviderName;
0397: }
0398:
0399: List getPortlets() {
0400: return m_Portlets;
0401: }
0402:
0403: Map getCollectionProperty(String channel, String key) {
0404: Map m = (Map) getTable(channel).lookup(key, TY_COLLECTION,
0405: false);
0406: if (m == null) {
0407: nullError("collection", channel, key);
0408: }
0409: return m;
0410: }
0411:
0412: Map getCollectionProperty(String channel, String key,
0413: boolean localized) {
0414: Map m = (Map) getTable(channel).lookup(key, TY_COLLECTION,
0415: localized);
0416: if (m == null) {
0417: nullError("collection", channel, key);
0418: }
0419: return m;
0420: }
0421:
0422: void setBooleanProperty(String channel, String key, boolean val) {
0423: getTable(channel).enter(key, TY_BOOL, new Boolean(val));
0424: }
0425:
0426: int getEditType(String channel) {
0427: String type = getStringProperty(channel, "editType");
0428:
0429: if (type.equalsIgnoreCase("edit_complete")) {
0430: return EDIT_COMPLETE;
0431: } else {
0432: return EDIT_SUBSET;
0433: }
0434: }
0435:
0436: Iterator getNames(String channel) {
0437: return getTable(channel).getNames();
0438: }
0439:
0440: void setIntegerProperty(String channel, String key, int val) {
0441: getTable(channel).enter(key, TY_INT, new Integer(val));
0442: }
0443:
0444: void setStringProperty(String channel, String key, String val) {
0445: getTable(channel).enter(key, TY_STRING, val);
0446: }
0447:
0448: void setProperty(String channel, String key, Object val) {
0449: getTable(channel).enter(key, getObjectType(val), val);
0450: }
0451:
0452: private static int getObjectType(Object val) {
0453: if (val instanceof String) {
0454: return TY_STRING;
0455: }
0456: if (val instanceof Integer) {
0457: return TY_INT;
0458: }
0459: if (val instanceof Boolean) {
0460: return TY_BOOL;
0461: }
0462: if (val instanceof Map) {
0463: return TY_COLLECTION;
0464: }
0465: throw new ContextError(
0466: "Illegal type of object in setProperty()");
0467: }
0468:
0469: boolean existsIntegerProperty(String channel, String name) {
0470: return getTable(channel).lookup(name, TY_INT, false) != null;
0471: }
0472:
0473: int getIntegerProperty(String channel, String key) {
0474: Integer iobj = (Integer) getTable(channel).lookup(key, TY_INT,
0475: false);
0476: if (iobj == null) {
0477: nullError("Integer", channel, key);
0478: }
0479: return iobj.intValue();
0480: }
0481:
0482: // This method does not correspond to a ProviderContext method. This reflects the
0483: // fact that we obtain our locale information from a user-defined file, rather than
0484: // the DSAME service.
0485:
0486: String getLocaleString() {
0487: return m_LocaleString;
0488: }
0489:
0490: // This does not correspond to a provider context method either. We obtain our channel
0491: // name from the component file.
0492:
0493: String getChannelName() {
0494: return m_ChannelName;
0495: }
0496:
0497: private void nullError(String type, String channel, String key) {
0498: throw new ContextError("No " + type + " property for key \""
0499: + key + "\" in channel \"" + channel + "\".");
0500: }
0501:
0502: private PropHashMap getTable(String channel) {
0503: if (channel.equals(m_ChannelName)) {
0504: if (m_OurChannel == null) {
0505: m_OurChannel = new PropHashMap(m_ChannelName);
0506: }
0507: return m_OurChannel;
0508: }
0509:
0510: for (int i = 0; i < m_OtherChannels.size(); ++i) {
0511: PropHashMap pm = (PropHashMap) m_OtherChannels.elementAt(i);
0512: if (pm.getName().equals(channel)) {
0513: return pm;
0514: }
0515: }
0516:
0517: PropHashMap pm = new PropHashMap(channel);
0518: m_OtherChannels.add(pm);
0519:
0520: return pm;
0521: }
0522:
0523: void setPropertyWriteState(int state)
0524: throws ProviderHarnessException {
0525: switch (state) {
0526: case WS_INITIAL_INPUT:
0527: m_AllowNewEntry = true;
0528: break;
0529: case WS_PROVIDER_RUN:
0530: m_AllowNewEntry = false;
0531: break;
0532: case WS_TOOL_ADMIN:
0533: m_AllowNewEntry = true;
0534: break;
0535: default:
0536: throw new ProviderHarnessException(
0537: "illegal state in setPropertyWriteState()");
0538: }
0539: }
0540:
0541: String[] getUserNames() {
0542: String nm[] = new String[m_UserNames.size()];
0543: for (int i = 0; i < m_UserNames.size(); ++i) {
0544: nm[i] = (String) m_UserNames.elementAt(i);
0545: }
0546: return nm;
0547: }
0548:
0549: // populate the m_LookupLocs array with the correct number of location strings,
0550: // based on m_LocaleString, in order of most specific to least specific.
0551:
0552: private void makeLocsArray() {
0553: StringTokenizer toks = new StringTokenizer(m_LocaleString, "_");
0554: int len = toks.countTokens();
0555: m_LookupLocs = new String[len];
0556: int idx = len;
0557: while (toks.hasMoreTokens()) {
0558: String pfx = idx == len ? "" : m_LookupLocs[idx] + "_";
0559: --idx;
0560: m_LookupLocs[idx] = pfx + toks.nextToken();
0561: }
0562: }
0563:
0564: private void init(String user, String usersfile, String compfile,
0565: String portAppDir, String configdir)
0566: throws ProviderHarnessException {
0567:
0568: setPropertyWriteState(WS_INITIAL_INPUT);
0569:
0570: DocumentBuilder db = null;
0571: try {
0572: DocumentBuilderFactory dbf = DocumentBuilderFactory
0573: .newInstance();
0574: db = dbf.newDocumentBuilder();
0575: } catch (Exception ex) {
0576: throw new ProviderHarnessException(
0577: "Failure creating document builder", ex);
0578: }
0579:
0580: // if dpPortlet is true, then process portlet file, otherwise,
0581: // process compfile. This sets up our channel name. Also,
0582: // any parameters entered from compfile will then take precedence over
0583: // the more global ones (PropHashMap() uses the FIRST entered.
0584: if (portAppDir != null) {
0585: Properties props = new Properties();
0586: Properties extPortXML = new Properties();
0587: Properties rolesProps = new Properties();
0588: Properties userProps = new Properties();
0589: try {
0590: rolesProps.load(new FileInputStream(configdir
0591: + "/desktop/" + ROLES_FILE));
0592: userProps.load(new FileInputStream(configdir
0593: + "/desktop/" + USERINFO_FILE));
0594: } catch (Exception exc) {
0595: //if the file does not exist, go on
0596: }
0597:
0598: //System.out.println("HarnessProperties.init(), loading propfile...");
0599: FileInputStream portletIn = null;
0600: FileInputStream portalIn = null;
0601: FileInputStream webIn = null;
0602:
0603: try {
0604: portalIn = new FileInputStream(portAppDir
0605: + "/WEB-INF/sun-portlet.xml");
0606: } catch (FileNotFoundException fne) {
0607: //sun-portlet.xml is optional, if it does not exist, we can ignore it
0608: }
0609:
0610: try {
0611: portletIn = new FileInputStream(portAppDir
0612: + "/WEB-INF/portlet.xml");
0613: webIn = new FileInputStream(portAppDir
0614: + "/WEB-INF/web.xml");
0615: props.load(new FileInputStream(portAppDir + "/WEB-INF/"
0616: + PDCONFIG_FILE));
0617: processPortFile(configdir, portletIn, portalIn, webIn,
0618: usersfile, props, rolesProps, userProps, user,
0619: db);
0620: } catch (Exception exc) {
0621: throw new ProviderHarnessException(
0622: "Failure reading portlet app dir - "
0623: + portAppDir
0624: + " or the following properties files - \n1."
0625: + portAppDir + "/WEB-INF/"
0626: + PDCONFIG_FILE + ", 2." + configdir
0627: + "/desktop/" + ROLES_FILE + ", 3. "
0628: + configdir + "/desktop/"
0629: + USERINFO_FILE, exc);
0630: }
0631: }
0632: if (compfile != null) {
0633:
0634: Document compdoc = null;
0635: Document userdoc = null;
0636:
0637: //System.out.println("HarnessProperties.init(), loading compfile...");
0638: try {
0639: db.setEntityResolver(new ParEntryEntityResolver());
0640: compdoc = db.parse(new FileInputStream(compfile));
0641: } catch (Exception ex) {
0642: throw new ProviderHarnessException(
0643: "Failure reading component xml - " + compfile,
0644: ex);
0645: }
0646: boolean haveProvider = processCompFileForNames(compdoc);
0647:
0648: // Next, the usersfile
0649:
0650: try {
0651: userdoc = db.parse(new FileInputStream(usersfile));
0652: } catch (Exception ex) {
0653: throw new ProviderHarnessException(
0654: "Failure reading users xml - " + usersfile, ex);
0655: }
0656: processUsersFile(user, userdoc);
0657:
0658: processCompFileProperties(compdoc, haveProvider);
0659: }
0660:
0661: // Finally, turn off "allow new entry" on our hashmaps, in preparation
0662: // for run.
0663:
0664: setPropertyWriteState(WS_PROVIDER_RUN);
0665: }
0666:
0667: //
0668: //Creates a property element inside the "Properties" bag for a
0669: //channel.
0670: //
0671: private Element createPropertyElement(String tagname, Document d,
0672: String name, String value) throws ProviderHarnessException {
0673: Element property = null;
0674: try {
0675: property = d.createElement(tagname);
0676: property.setAttribute(ATR_NAME, name);
0677: property.setAttribute(ATR_VALUE, value);
0678: } catch (Exception ex) {
0679: throw new ProviderHarnessException(
0680: "Failure creating element - " + tagname, ex);
0681: }
0682: return property;
0683: }
0684:
0685: //
0686: //Creates a "Channel" element inside in a document.
0687: //
0688: private Element createChannelElement(String providerName,
0689: Document doc) throws ProviderHarnessException {
0690:
0691: String channelName = providerName.substring("__Portlet__"
0692: .length(), providerName.length());
0693: channelName = channelName.replace('.', '_');
0694: m_Portlets.add(channelName);
0695: //System.out.println("HarnessProperties.createChannelElement(), channel name: "+channelName);
0696: Element channelElement = doc.createElement(TAG_CHANNEL);
0697: channelElement.setAttribute(ATR_NAME, channelName);
0698: channelElement.setAttribute(ATR_PROVIDER, providerName);
0699: Element propertiesElement = doc.createElement(TAG_PROPERTIES);
0700: propertiesElement.appendChild(createPropertyElement(TAG_STRING,
0701: doc, "title", providerName));
0702: propertiesElement.appendChild(createPropertyElement(TAG_STRING,
0703: doc, "description", providerName));
0704: propertiesElement.appendChild(createPropertyElement(TAG_STRING,
0705: doc, "width", "thick"));
0706: channelElement.appendChild(propertiesElement);
0707:
0708: return channelElement;
0709:
0710: }
0711:
0712: //
0713: // The "portlet file" is the portlet deployment descriptor file,
0714: // We use the Portlet deployer code to process the portlet file,
0715: // and create the provider display profile entries, and also calls
0716: // the local method <code>createChannelElement()</code> to
0717: // create the channel display profile entries.
0718: // After the provider and channel elements are created, we enter
0719: // them into the PropHashMap structure.
0720: //
0721: private void processPortFile(String configdir, FileInputStream in,
0722: FileInputStream extIn, FileInputStream webIn,
0723: String usersfile, Properties props, Properties rolesProps,
0724: Properties userinfoProps, String user, DocumentBuilder db)
0725: throws ProviderHarnessException {
0726:
0727: PDProviderEntryGenerator providerGen = null;
0728: List providerElements = null;
0729: List providerNames = null;
0730: List webAppRoles = null;
0731:
0732: try {
0733: webAppRoles = PDWebAppUpdater.getRoles(webIn);
0734: System.setProperty("DDSchemaLocation", configdir);
0735: providerGen = new PDProviderEntryGenerator(in, extIn,
0736: props, APP_NAME);
0737: providerElements = providerGen.createProviderElements(
0738: rolesProps, userinfoProps, webAppRoles);
0739: providerNames = providerGen.getProviderNames();
0740: } catch (Exception exc) {
0741: throw new ProviderHarnessException(
0742: "Error instantiating provider entry generator.",
0743: exc);
0744: }
0745:
0746: PropHashMap pm = null;
0747: Document doc = null;
0748: String providerName = null;
0749:
0750: for (int i = 0; i < providerElements.size(); i++) {
0751: doc = db.newDocument();
0752: providerName = (String) providerNames.get(i);
0753: Element celt = createChannelElement(providerName, doc);
0754: Element pelt = (Element) providerElements.get(i);
0755: String channelName = celt.getAttribute(ATR_NAME);
0756: System.out
0757: .println("HarnessProperties.processPortFile(), provider name: "
0758: + providerName);
0759: System.out
0760: .println("HarnessProperties.processPortFile(), channel name: "
0761: + channelName);
0762:
0763: printElement(pelt);
0764:
0765: pm = getTable(channelName);
0766:
0767: try {
0768: pm.enter(getPropertiesElement(pelt));
0769: pm.enter(getPropertiesElement(celt));
0770: } catch (Exception ex) {
0771: throw new ProviderHarnessException(
0772: "Error in channel properties from ParEntry.",
0773: ex);
0774: }
0775:
0776: // Next, the usersfile
0777: try {
0778: doc = db.parse(new FileInputStream(usersfile));
0779: } catch (Exception ex) {
0780: throw new ProviderHarnessException(
0781: "Failure reading users xml - " + usersfile, ex);
0782: }
0783: processUsersFile(user, doc);
0784: }
0785: }
0786:
0787: private Element getPropertiesElement(Element e) {
0788: NodeList childNodes = e.getChildNodes();
0789: int numChildren = childNodes.getLength();
0790: Element properties = null;
0791:
0792: for (int i = 0; i < numChildren; i++) {
0793: Node childNode = childNodes.item(i);
0794: Element childElement = (Element) childNode;
0795: String childTagName = childElement.getTagName();
0796: //System.out.println("HarnessProperties.getPropertiesElement(), getPropertyElement, tag: "+childTagName);
0797: if (childTagName.equals("Properties")) {
0798: properties = childElement;
0799: }
0800: }
0801: return properties;
0802: }
0803:
0804: private void printElement(Element e) {
0805: NodeList childNodes = e.getChildNodes();
0806: int numChildren = childNodes.getLength();
0807:
0808: for (int i = 0; i < numChildren; i++) {
0809: Node childNode = childNodes.item(i);
0810: Element childElement = (Element) childNode;
0811: String childTagName = childElement.getTagName();
0812: String n = childElement.getAttribute("name");
0813: String v = childElement.getAttribute("value");
0814: System.out.println("HarnessProperties.printElement, name: "
0815: + n);
0816: System.out
0817: .println("HarnessProperties.printElement, value: "
0818: + v);
0819: System.out
0820: .println("HarnessProperties.printElement, element:"
0821: + childElement.toString());
0822:
0823: printElement(childElement);
0824: }
0825:
0826: }
0827:
0828: // The "component file" is a ParEntry, which we can use the Par
0829: // code to process.
0830:
0831: private boolean processCompFileForNames(Document doc)
0832: throws ProviderHarnessException {
0833:
0834: boolean haveProvider = false;
0835:
0836: try {
0837: haveProvider = (Par.applicableDocTypes(doc) & ExtractOp.TYPE_PROVIDER) != 0;
0838: m_ChannelName = Par.getChannelName(doc);
0839: if (haveProvider) {
0840: m_ProviderName = Par.getProviderName(doc);
0841: } else {
0842: m_ProviderName = Par.getProviderNameFromChannel(doc);
0843: }
0844: } catch (Exception ex) {
0845: throw new ProviderHarnessException(
0846: "Failure obtaining provider / channel from ParEntry.",
0847: ex);
0848: }
0849:
0850: // we get the "requiredClass" attribute ourselves, since that isn't really part
0851: // of a normal parEntry.
0852:
0853: Element elt = doc.getDocumentElement();
0854: m_ProviderClass = elt.getAttribute("requiredClass");
0855: if (m_ProviderClass == null || m_ProviderClass.length() == 0) {
0856: throw new ProviderHarnessException(
0857: "Failure extracting requiredClass from ParEntry.");
0858: }
0859:
0860: return haveProvider;
0861: }
0862:
0863: private void processCompFileProperties(Document doc,
0864: boolean haveProvider) throws ProviderHarnessException {
0865:
0866: PropHashMap pm = getTable(m_ChannelName);
0867:
0868: Element pelt = null;
0869: try {
0870: pelt = Par.getChannelProperties(doc);
0871: } catch (Exception ex) {
0872: throw new ProviderHarnessException(
0873: "Failure obtaining channel properties from ParEntry.",
0874: ex);
0875: }
0876: try {
0877: pm.enter(pelt);
0878: } catch (Exception ex) {
0879: throw new ProviderHarnessException(
0880: "Error in channel properties from ParEntry.", ex);
0881: }
0882:
0883: if (haveProvider) {
0884: try {
0885: pelt = Par.getProviderProperties(doc);
0886: } catch (Exception ex) {
0887: throw new ProviderHarnessException(
0888: "Failure obtaining provider properties from ParEntry.",
0889: ex);
0890: }
0891: try {
0892: pm.enter(pelt);
0893: } catch (Exception ex) {
0894: throw new ProviderHarnessException(
0895: "Error in provider properties from ParEntry.",
0896: ex);
0897: }
0898: }
0899: //System.out.println("HarnessProperties.processCompFile(), provider name: " + m_ProviderName + " channel name: " + m_ChannelName);
0900: }
0901:
0902: private void processUsersFile(String user, Document doc)
0903: throws ProviderHarnessException {
0904:
0905: UsersFile uf = UsersFile.makeUsersFile(doc);
0906:
0907: uf.getUserNames(m_UserNames);
0908:
0909: m_LocaleString = uf.getLocale(user);
0910: makeLocsArray();
0911:
0912: PropHashMap pm = getTable(m_ChannelName);
0913: try {
0914: pm.enter(uf.getUserProps(user));
0915: } catch (Exception ex) {
0916: throw new ProviderHarnessException(
0917: "Users.xml - error in <Properties> for user "
0918: + user, ex);
0919: }
0920: try {
0921: pm.enter(uf.getGlobalProps());
0922: } catch (Exception ex) {
0923: throw new ProviderHarnessException(
0924: "Users.xml - error in <Global><Properties>", ex);
0925: }
0926:
0927: Vector v = new Vector();
0928:
0929: uf.getUserChannelList(user, v);
0930: for (int i = 0; i < v.size(); ++i) {
0931: String chan = (String) v.elementAt(i);
0932: pm = getTable(chan);
0933: try {
0934: pm.enter(uf.getUserChannelProps(user, chan));
0935: } catch (Exception ex) {
0936: throw new ProviderHarnessException(
0937: "Users.xml - error in <Properties> for channel "
0938: + chan + ", user " + user, ex);
0939: }
0940: }
0941:
0942: v.clear();
0943: uf.getGlobalChannelList(v);
0944: for (int i = 0; i < v.size(); ++i) {
0945: String chan = (String) v.elementAt(i);
0946: pm = getTable(chan);
0947: try {
0948: pm.enter(uf.getGlobalChannelProps(chan));
0949: } catch (Exception ex) {
0950: throw new ProviderHarnessException(
0951: "Users.xml - error in <Properties> for <Global> channel "
0952: + chan, ex);
0953: }
0954: }
0955: }
0956:
0957: private void setEditList(HttpServletRequest req)
0958: throws ProviderHarnessException {
0959:
0960: // get the Props map for the right channel.
0961:
0962: String m_EditChannel = req.getParameter(ARG_LIST_CHANNEL);
0963: if (m_EditChannel == null) {
0964: m_EditChannel = m_ChannelName;
0965: }
0966: m_EditProps = getTable(m_EditChannel);
0967:
0968: // Get the "variant" parameter, which represents a naviagtion choice,
0969: // if present. Remember to null it out after we make use of it.
0970:
0971: String var = req.getParameter(ARG_LIST_VAR);
0972:
0973: // get the locale, and the correct top-level flattened
0974: // map.
0975:
0976: m_EditLocale = req.getParameter(ARG_LIST_LOCALE);
0977: if (m_EditLocale == null && var != null
0978: && var.charAt(0) == ARGLVAR_LOC) {
0979: m_EditLocale = var.substring(1);
0980: var = null;
0981: }
0982:
0983: setEditListFromLocale(req, var);
0984: }
0985:
0986: // Reuse this logic to reset our navigation to the locale when we just added
0987: // a locale-specific entry.
0988:
0989: private void setEditListFromLocale(HttpServletRequest req,
0990: String var) throws ProviderHarnessException {
0991:
0992: m_EditPath.clear();
0993: m_EditCollNames.clear();
0994: m_EditAtomicMap = m_EditProps.getFlatMap(m_EditLocale);
0995: m_EditCurrentColl = null;
0996:
0997: // Process collection parameters to find the right sub-collection,
0998: // if applicable.
0999:
1000: for (int i = 0; i < 20; ++i) {
1001: String parm = ARG_LIST_COLL + i;
1002: String cnm = req.getParameter(parm);
1003: if (cnm == null) {
1004: if (var == null || var.charAt(0) != ARGLVAR_COLL) {
1005: break;
1006: }
1007: cnm = var.substring(1);
1008: var = null;
1009: }
1010: HashMap m;
1011: try {
1012: m_EditCurrentColl = (HashMap) m_EditAtomicMap.get(cnm);
1013: if (m_EditCurrentColl == null) {
1014: throw new ProviderHarnessException(
1015: "Expected collection property \"" + cnm
1016: + "\" not present.");
1017: }
1018: m = (HashMap) m_EditCurrentColl.clone();
1019: } catch (ClassCastException ex) {
1020: throw new ProviderHarnessException("Property \"" + cnm
1021: + "\" was not a collection.");
1022: }
1023: if (m == null) {
1024: throw new ProviderHarnessException(
1025: "Could not find collection \"" + cnm + "\"");
1026: }
1027: m_EditAtomicMap = m;
1028: m_EditPath.add(cnm);
1029: }
1030:
1031: // Now, separate the collections out of our map into the collection names vector.
1032:
1033: Iterator it = m_EditAtomicMap.keySet().iterator();
1034: while (it.hasNext()) {
1035: String key = (String) it.next();
1036: Object obj = m_EditAtomicMap.get(key);
1037: if (obj != null && obj instanceof Map) {
1038: it.remove();
1039: m_EditCollNames.add(key);
1040: }
1041: }
1042: }
1043:
1044: private void performOperation(String op, HttpServletRequest req)
1045: throws ProviderHarnessException {
1046:
1047: String nm = req.getParameter(ARG_LIST_ITEM);
1048:
1049: if (op.equals(ARGOP_DELETE)) {
1050: if (nm == null) {
1051: throw new ProviderHarnessException(
1052: "Delete specified with no item.");
1053: }
1054: m_EditAtomicMap.remove(nm);
1055: if (m_EditPath.size() == 0) {
1056: m_EditProps.removeProperty(nm, m_EditLocale);
1057: }
1058: return;
1059: }
1060:
1061: // All remaining operations involve setting up an object and type. If
1062: // we don't recognize the operation, we will wind up with type = TY_NONE.
1063: // We set up everything for "add", which we will override in the "change"
1064: // logic.
1065:
1066: int type = TY_NONE;
1067: String val = req.getParameter(ARG_ADD_VALUE);
1068: String setnm = req.getParameter(ARG_ADD_NAME);
1069: String loc = m_EditLocale;
1070: String useloc = req.getParameter(ARG_ADD_USELOC);
1071: if (useloc != null && useloc.toLowerCase().charAt(0) == 'y') {
1072: loc = req.getParameter(ARG_ADDLOC_LANG);
1073: if (loc != null && !loc.equals("")) {
1074: String c = req.getParameter(ARG_ADDLOC_COUNTRY);
1075: if (c != null && !c.equals("")) {
1076: loc += "_" + c;
1077: c = req.getParameter(ARG_ADDLOC_VAR);
1078: if (c != null && !c.equals("")) {
1079: loc += "_" + c;
1080: }
1081: }
1082: }
1083: }
1084: if (loc != null && loc.equals("")) {
1085: loc = null;
1086: }
1087:
1088: if (op.equals(ARGOP_CHANGE)) {
1089: if (nm == null) {
1090: throw new ProviderHarnessException(
1091: "Change specified with no item.");
1092: }
1093:
1094: val = req.getParameter(ARG_CHANGE_VALUE);
1095: loc = m_EditLocale;
1096: setnm = nm;
1097:
1098: Object obj = m_EditAtomicMap.get(nm);
1099: if (obj == null) {
1100: throw new ProviderHarnessException(
1101: "Changed property does not exist.");
1102: }
1103:
1104: type = getObjectType(obj);
1105: }
1106:
1107: if (op.equals(ARGOP_ADDSTRING)) {
1108: type = TY_STRING;
1109: }
1110:
1111: if (op.equals(ARGOP_ADDBOOLEAN)) {
1112: type = TY_BOOL;
1113: }
1114:
1115: if (op.equals(ARGOP_ADDINTEGER)) {
1116: type = TY_INT;
1117: }
1118:
1119: if (op.equals(ARGOP_ADDCOLLECTION)) {
1120: type = TY_COLLECTION;
1121: }
1122:
1123: if (type != TY_COLLECTION && val == null) {
1124: throw new ProviderHarnessException(
1125: "No property value specified for operation.");
1126: }
1127: if (setnm == null) {
1128: throw new ProviderHarnessException(
1129: "No property name specified for operation.");
1130: }
1131:
1132: Object obj = null;
1133: switch (type) {
1134: case TY_STRING:
1135: obj = val;
1136: break;
1137: case TY_BOOL:
1138: obj = Boolean.valueOf(val);
1139: break;
1140: case TY_INT:
1141: try {
1142: obj = Integer.valueOf(val);
1143: } catch (Exception ex) {
1144: throw new ContextError(
1145: "Conversion error setting integer property.");
1146: }
1147: break;
1148: case TY_COLLECTION:
1149: obj = new HashMap();
1150: break;
1151: default:
1152: throw new ProviderHarnessException(
1153: "Unknown type for property or unrecognized operation.");
1154: }
1155:
1156: // Do this first, so that we preserve our edit state if this throws
1157: // an exception. When we set a locale-specific entry from root,
1158: // navigate into the locale. In this case, the m_EditAtomicMap.put()
1159: // which follows will be redundant, but so what.
1160:
1161: if (m_EditPath.size() == 0) {
1162: m_EditProps.enter(setnm, type, loc, obj);
1163: if (loc != null && m_EditLocale == null) {
1164: m_EditLocale = loc;
1165: setEditListFromLocale(req, null);
1166: }
1167: }
1168:
1169: // Fix up current edit information.
1170:
1171: if (type == TY_COLLECTION) {
1172: m_EditCollNames.add(setnm);
1173: } else {
1174: m_EditAtomicMap.put(setnm, obj);
1175: }
1176:
1177: if (m_EditCurrentColl != null) {
1178: m_EditCurrentColl.put(setnm, obj);
1179: }
1180: }
1181:
1182: // m_LookupLocs[] is an array of strings representing the various less specific
1183: // parts of m_LocaleString, in appropriate search order so that we don't have to
1184: // keep parsing m_LocaleString.
1185:
1186: private String m_ChannelName;
1187: private String m_ProviderName;
1188: private String m_LocaleString;
1189: private String m_LookupLocs[];
1190: private Vector m_UserNames;
1191:
1192: private String m_ProviderClass;
1193:
1194: private boolean m_AllowNewEntry;
1195:
1196: // We keep a distinguished HashMap for our channel, plus a vector
1197: // of hashmaps for other channels. This reflects the fact that a
1198: // vast majority of lookups will be against our own channel, and
1199: // in most cases, the "other channels" vector will, in fact, be empty.
1200:
1201: // Keeping them separate also cuts down on the complexity of providing the
1202: // iterator for getNames().
1203:
1204: private PropHashMap m_OurChannel;
1205: private Vector m_OtherChannels;
1206: private List m_Portlets = new ArrayList();
1207:
1208: // Edit support
1209:
1210: private PropHashMap m_EditProps;
1211: private String m_EditChannel;
1212: private HashMap m_EditAtomicMap = null;
1213: private HashMap m_EditCurrentColl = null;
1214: private Vector m_EditPath = new Vector();
1215: private Vector m_EditCollNames = new Vector();
1216: private String m_EditLocale;
1217: private String m_EditError;
1218:
1219: // Encodes for the types. Since we are surfacing seperate API for
1220: // lookup of each type, we do it this way, rather than by reflecting
1221: // the type of the entered objects.
1222:
1223: private static final int TY_NONE = 0;
1224: private static final int TY_STRING = 1;
1225: private static final int TY_BOOL = 2;
1226: private static final int TY_INT = 3;
1227: private static final int TY_COLLECTION = 4;
1228:
1229: // To simulate the way iPS property lookup works for DP implementation,
1230: // we key each property twice - by just its name, and its name and type.
1231: // It is possible to make type-specific requests to iPS and get two
1232: // different objects with the same name, based on type.
1233:
1234: // inner class PropHashMap encapsulates the iPS entry and lookup semantics
1235: // involving types and locales. It is keyed by channel name.
1236:
1237: class PropHashMap extends HashMap {
1238:
1239: PropHashMap(String name) {
1240: super ();
1241: m_Name = name;
1242: }
1243:
1244: String getName() {
1245: return m_Name;
1246: }
1247:
1248: void enter(String key, int type, Object obj) {
1249: checkPut(compositeKey(key, type, null), obj);
1250: checkPut(compositeKey(key, TY_NONE, null), obj);
1251: }
1252:
1253: void removeProperty(String key, String loc) {
1254: remove(compositeKey(key, TY_NONE, loc));
1255: remove(compositeKey(key, TY_STRING, loc));
1256: remove(compositeKey(key, TY_INT, loc));
1257: remove(compositeKey(key, TY_BOOL, loc));
1258: remove(compositeKey(key, TY_COLLECTION, loc));
1259: }
1260:
1261: // Note - currently, we only look up strings via locale so a
1262: // typeless key with a locale is not really neccesary, but we do
1263: // it anyway.
1264:
1265: void enter(String key, int type, String loc, Object obj) {
1266: checkPut(compositeKey(key, type, loc), obj);
1267: checkPut(compositeKey(key, TY_NONE, loc), obj);
1268: }
1269:
1270: // decode and enter a Properties element.
1271:
1272: void enter(Element elt) throws ProviderHarnessException {
1273: enter(elt, null, null);
1274: }
1275:
1276: // getNames has to "collapse" all our keys, removing prefixes and resultant
1277: // multiple copies.
1278:
1279: Iterator getNames() {
1280: HashMap hm = new HashMap();
1281:
1282: Iterator it = keySet().iterator();
1283: while (it.hasNext()) {
1284: String str = (String) it.next();
1285: int idx = str.indexOf(KEY_DELIMETER);
1286: if (idx >= 0) {
1287: hm.put(str.substring(idx + 1), "");
1288: }
1289: }
1290:
1291: return hm.keySet().iterator();
1292: }
1293:
1294: Object lookup(String key, int type, boolean localized) {
1295: if (localized) {
1296: for (int i = 0; i < m_LookupLocs.length; ++i) {
1297: String ckey = compositeKey(key, type,
1298: m_LookupLocs[i]);
1299: Object obj = get(ckey);
1300: if (obj != null) {
1301: return obj;
1302: }
1303: }
1304: }
1305:
1306: return get(compositeKey(key, type, null));
1307: }
1308:
1309: // get a flat hashmap for editing which reflects just the names
1310: // for a particular locale. NOTE - this depends on the way we
1311: // do compositeKey(). If that is changed, we have to change
1312: // this logic as well.
1313:
1314: HashMap getFlatMap(String loc) {
1315:
1316: HashMap map = new HashMap();
1317:
1318: Iterator it = keySet().iterator();
1319: while (it.hasNext()) {
1320: String key = (String) it.next();
1321:
1322: int idx = key.indexOf(KEY_DELIMETER);
1323: if (idx <= 0) {
1324: continue; // shouldn't actually happen
1325: }
1326:
1327: // Strip off the name and the stuff preceding it.
1328:
1329: String nm = key.substring(idx + 1);
1330: String pfx = key.substring(0, idx);
1331:
1332: int lidx = pfx.indexOf(LOC_DELIMETER);
1333: if (lidx <= 0) {
1334: if (loc != null) {
1335: continue;
1336: }
1337: } else {
1338: String keyloc = pfx.substring(0, lidx);
1339: if (loc == null) {
1340: continue;
1341: }
1342: if (!keyloc.equals(loc)) {
1343: continue;
1344: }
1345: }
1346:
1347: // key matches our location, or loc is null and key is not locale
1348: // specific. Now, we enter our object into the flattened hashmap
1349: // under just the name portion of the key if we haven't already -
1350: // we expect to come through here twice, for the type-specific and
1351: // TY_NONE versions of the key.
1352:
1353: if (map.get(nm) == null) {
1354: map.put(nm, get(key));
1355: }
1356: }
1357:
1358: return map;
1359: }
1360:
1361: // This also depends on the compositeKey format.
1362:
1363: String[] getLocaleList() {
1364:
1365: HashMap m = new HashMap();
1366: Iterator it = keySet().iterator();
1367:
1368: while (it.hasNext()) {
1369: String key = (String) it.next();
1370:
1371: int idx = key.indexOf(KEY_DELIMETER);
1372: if (idx <= 0) {
1373: continue; // shouldn't actually happen
1374: }
1375:
1376: // we strip off the key first in case the key contains
1377: // the locale delimter.
1378:
1379: String pfx = key.substring(0, idx);
1380:
1381: int lidx = pfx.indexOf(LOC_DELIMETER);
1382: if (lidx <= 0) {
1383: continue;
1384: }
1385: String loc = key.substring(0, lidx);
1386: m.put(loc, loc);
1387: }
1388:
1389: return (String[]) m.keySet().toArray(new String[0]);
1390: }
1391:
1392: // place the location and type at the front of the composite
1393: // key since these are restricted strings that cannot conflict
1394: // with the KEY_DELIMETER. By assuring that the arbitrary key
1395: // ALWAYS follows KEY_DELIMETER, its contents cannot conflict.
1396: // Entering a specific "none" type also allows us to have only
1397: // one lookup method.
1398:
1399: // Note - if this is changed, see the getFlatMap() method, which
1400: // may also have to change.
1401:
1402: private String compositeKey(String key, int type, String loc) {
1403: String ckey = String.valueOf(type) + KEY_DELIMETER + key;
1404: if (loc == null) {
1405: return ckey;
1406: }
1407: return loc + LOC_DELIMETER + ckey;
1408: }
1409:
1410: // If AllowNewEntry is true, we are populating from XML files or an "admin"
1411: // screen. OverWrite = false means that we do not set already set keys.
1412: // This reflects the way iPS reads XML files - multiple names aren't prevented,
1413: // and there is no stated guarantee as to which property you get if there are
1414: // multiple list entries, but, in fact, it's the first one you get.
1415:
1416: // If AllowNewEntry is false, we are running the user's code - it is an
1417: // error to attempt to set a parameter which does not already exist.
1418:
1419: private void checkPut(String key, Object obj) {
1420: if (get(key) == null) {
1421: if (m_AllowNewEntry) {
1422: put(key, obj);
1423: } else {
1424: throw new ContextError(
1425: "Attempt to set non-existent parameter.");
1426: }
1427: return;
1428: }
1429: put(key, obj);
1430: }
1431:
1432: // The actual work for recursively descending a Properties XML and entering
1433: // the contents. Recursively called to process Locale's and collections - we
1434: // pass in the current locale string, and current collection map, either of
1435: // which may be null if not processing the appropriate item.
1436:
1437: private void enter(Element elt, String locale, HashMap map)
1438: throws ProviderHarnessException {
1439:
1440: NodeList kids = elt.getChildNodes();
1441:
1442: for (int i = 0; i < kids.getLength(); ++i) {
1443: Node child = kids.item(i);
1444: if (child instanceof Element) {
1445: Element chelt = (Element) child;
1446: String tagnm = chelt.getNodeName();
1447:
1448: if (locale != null && !tagnm.equals("String")
1449: && !tagnm.equals("Collection")) {
1450: throw new ProviderHarnessException(
1451: "<Locale> can only contain <String> and <Collection>.");
1452: }
1453:
1454: // Process a Locale element.
1455:
1456: if (chelt.getNodeName().equals("Locale")) {
1457:
1458: if (map != null) {
1459: throw new ProviderHarnessException(
1460: "<Collection> may not contain <Locale>.");
1461: }
1462:
1463: String newloc = getAttribute(chelt, "language");
1464: if (newloc == null) {
1465: enter(chelt, null, null); // oh well.
1466: continue;
1467: }
1468:
1469: String country = getAttribute(chelt, "country");
1470: if (country != null) {
1471: newloc += "_" + country;
1472: String var = getAttribute(chelt, "variant");
1473: if (var != null) {
1474: newloc += "_" + var;
1475: }
1476: }
1477:
1478: enter(chelt, newloc, null);
1479: continue;
1480: }
1481:
1482: // get the name. Not much we can do with a nameless
1483: // element if we are not putting it in a collection.
1484:
1485: String nm = getAttribute(chelt, "name");
1486: if (nm == null && map == null) {
1487: continue;
1488: }
1489:
1490: // At this point, we are going to obtain an object to enter and a type.
1491:
1492: Object obj = null;
1493: int type = TY_NONE;
1494:
1495: if (chelt.getNodeName().equals("Collection")) {
1496: HashMap coll = new HashMap();
1497: enter(chelt, null, coll);
1498: obj = coll;
1499: type = TY_COLLECTION;
1500: }
1501: if (chelt.getNodeName().equals("Integer")) {
1502: String val = getAttribute(chelt, "value", "0");
1503: try {
1504: obj = Integer.valueOf(val);
1505: } catch (Exception ex) {
1506: throw new ProviderHarnessException(
1507: "<Integer> with bad value - " + val,
1508: ex);
1509: }
1510: type = TY_INT;
1511: }
1512: if (chelt.getNodeName().equals("String")) {
1513: // yeah, I know - chelt.getAttribute() would work in this case.
1514: obj = getAttribute(chelt, "value", "");
1515: type = TY_STRING;
1516: }
1517: if (chelt.getNodeName().equals("Boolean")) {
1518: String val = getAttribute(chelt, "value",
1519: "false");
1520: try {
1521: obj = Boolean.valueOf(val);
1522: } catch (Exception ex) {
1523: throw new ProviderHarnessException(
1524: "<Boolean> with bad value - " + val,
1525: ex);
1526: }
1527: type = TY_BOOL;
1528: }
1529:
1530: // If we didn't recognize it, skip it.
1531: if (obj == null) {
1532: continue;
1533: }
1534:
1535: // If we are processing a collection, put it in the collection.
1536: if (map != null) {
1537: map.put(nm != null ? nm : obj, obj);
1538: continue;
1539: }
1540:
1541: // Not a collection. Just enter it.
1542: if (locale == null) {
1543: enter(nm, type, obj);
1544: continue;
1545: }
1546: enter(nm, type, locale, obj);
1547: }
1548: }
1549: }
1550:
1551: // Attribute lookup conveniences.
1552:
1553: private String getAttribute(Element elt, String att) {
1554: Attr a = elt.getAttributeNode(att);
1555: if (a == null) {
1556: return null;
1557: }
1558: return a.getValue();
1559: }
1560:
1561: private String getAttribute(Element elt, String att, String def) {
1562: String val = getAttribute(elt, att);
1563: return val == null ? def : val;
1564: }
1565:
1566: private String m_Name;
1567:
1568: private static final char KEY_DELIMETER = '#';
1569: private static final char LOC_DELIMETER = '+';
1570: }
1571: }
|