001: /**
002: * Copyright (C) 2001-2005 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.mapper.lib;
018:
019: import org.objectweb.jorm.api.PMapper;
020: import org.objectweb.speedo.api.SpeedoProperties;
021: import org.objectweb.speedo.mapper.api.ClassPropertyManager;
022: import org.objectweb.speedo.mim.api.HomeItf;
023: import org.objectweb.speedo.tools.StringReplace;
024: import org.objectweb.util.monolog.api.BasicLevel;
025: import org.objectweb.util.monolog.api.Logger;
026:
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.Properties;
031: import java.util.regex.Pattern;
032:
033: public class ClassPropertiesManager implements SpeedoProperties {
034:
035: public final static char FIELD_SEP = '#';
036:
037: final Properties speedoProperties;
038:
039: final HashMap name2prop;
040:
041: final HashMap pattern2prop;
042:
043: /**
044: * key = property prefix
045: * value = ClassProperty instance
046: */
047: final HashMap prefix2Impl;
048:
049: /**
050: * The mapper holding homes of the persistent classes
051: */
052: protected PMapper mapper = null;
053:
054: protected Logger logger;
055:
056: public ClassPropertiesManager() {
057: speedoProperties = new Properties();
058: name2prop = new HashMap();
059: pattern2prop = new HashMap();
060: prefix2Impl = new HashMap();
061: addClassPropertyManager(new CPMCacheClassPolicy());
062: addClassPropertyManager(new CPMShareablePolicy());
063: addClassPropertyManager(new CPMTransactionLockingLevel());
064: addClassPropertyManager(new CPMUserCachePolicy());
065: addClassPropertyManager(new CPMPrefetchOnQuery());
066: addClassPropertyManager(new CPMPrefetchOnExtent());
067: addClassPropertyManager(new CPMPrefetchOnGenClass());
068: }
069:
070: public void addClassPropertyManager(ClassPropertyManager cpm) {
071: prefix2Impl.put(cpm.getName(), cpm);
072: }
073:
074: /**
075: * Sets all properties.
076: * @param props
077: */
078: public void addProperties(Properties props) {
079: if (props == null || props.size() == 0) {
080: return;
081: }
082: String[] classNames = mapper.getMappedClasses();
083: boolean apply = classNames != null && classNames.length > 0;
084: for (Iterator it = props.entrySet().iterator(); it.hasNext();) {
085: Map.Entry me = (Map.Entry) it.next();
086: Prop prop = createProperty((String) me.getKey(),
087: (String) me.getValue());
088: if (apply) { // && prop.patternIsRegExp
089: applyProperty(prop, classNames);
090: }
091: }
092: }
093:
094: /**
095: * Set a property
096: * @param name is the property name
097: * @param value is the property value
098: */
099: public void addProperty(String name, String value) {
100: if (value == null || value.length() == 0) {
101: removeProperty(name);
102: } else {
103: Prop prop = createProperty(name, value);
104: if (prop.patternIsRegExp) {
105: String[] classNames = mapper.getMappedClasses();
106: if (classNames != null && classNames.length > 0) {
107: applyProperty(prop, classNames);
108: }
109: }
110: }
111: }
112:
113: /**
114: * Applies current properties to a home of a persistent class.
115: * @param sh is the home of the persistent class.
116: */
117: public void applyProperties(HomeItf sh) {
118: if (pattern2prop.size() == 0) {
119: for (Iterator it = prefix2Impl.values().iterator(); it
120: .hasNext();) {
121: ClassPropertyManager cpm = (ClassPropertyManager) it
122: .next();
123: cpm.applyDefault(sh, speedoProperties, logger);
124: }
125: return;
126: }
127: String path = sh.getPath();
128: for (Iterator iter = pattern2prop.values().iterator(); iter
129: .hasNext();) {
130: Prop prop = (Prop) iter.next();
131: if (prop.match(path)) {
132: prop.applyProperty(sh);
133: }
134: }
135: }
136:
137: /**
138: * Applies current properties to a home of a generic persistent class.
139: * @param gcHome is the home of the persistent class.
140: */
141: public void applyProperties(HomeItf gcHome, HomeItf refHome) {
142: if (pattern2prop.size() == 0) {
143: for (Iterator it = prefix2Impl.values().iterator(); it
144: .hasNext();) {
145: ClassPropertyManager cpm = (ClassPropertyManager) it
146: .next();
147: cpm.applyDefault(gcHome, refHome, speedoProperties,
148: logger);
149: }
150: return;
151: }
152: String path = gcHome.getPath();
153: for (Iterator iter = pattern2prop.values().iterator(); iter
154: .hasNext();) {
155: Prop prop = (Prop) iter.next();
156: if (prop.match(path)) {
157: prop.applyProperty(gcHome, refHome);
158: }
159: }
160: }
161:
162: public Properties getProperties() {
163: return speedoProperties;
164: }
165:
166: private synchronized Prop createProperty(String name, String value) {
167: if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
168: logger.log(BasicLevel.DEBUG, "Set property " + name + "="
169: + value);
170: }
171: return new Prop(name, value);
172: }
173:
174: private synchronized void removeProperty(String name) {
175: if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
176: logger.log(BasicLevel.DEBUG, "Remove property " + name);
177: }
178: speedoProperties.remove(name);
179: Prop oldProp = (Prop) name2prop.remove(name);
180: if (oldProp != null && oldProp.pa != null) {
181: pattern2prop.remove(oldProp.pa);
182: }
183: }
184:
185: /**
186: * Internal representation of a property.
187: * A property has a pattern if it follows this profile of
188: * expression: xxx(yyy) where xxx is the prefix and yyy is the pattern
189: * characterizing class names.
190: *
191: * @author S.Chassande-Barrioz
192: */
193: private final class Prop {
194: /**
195: * The name of the property
196: */
197: public final String name;
198: /**
199: * The value of the property
200: */
201: public final String value;
202: public final String prefix;
203: public final String pattern;
204: public final boolean patternOnField;
205: public final boolean patternIsRegExp;
206: public final Pattern pa;
207: public ClassPropertyManager cpm;
208:
209: public Prop(String n, String v) {
210: this .name = n;
211: this .value = v;
212: speedoProperties.put(name, value);
213: Prop oldProp = (Prop) name2prop.put(name, this );
214: if (oldProp != null && oldProp.pa != null) {
215: pattern2prop.remove(oldProp.pa);
216: }
217: int idx1 = name.indexOf('(');
218: int idx2 = name.indexOf(')');
219: if (idx2 > idx1 && idx1 > 0) {
220: this .prefix = name.substring(0, idx1);
221: cpm = (ClassPropertyManager) prefix2Impl
222: .get(this .prefix);
223: this .pattern = name.substring(idx1 + 1, idx2);
224: this .patternIsRegExp = this .pattern != null
225: && (this .pattern.indexOf('*') != -1 || this .pattern
226: .indexOf('?') != -1);
227: this .patternOnField = pattern.indexOf(FIELD_SEP) > 0;
228: if (this .patternIsRegExp) {
229: this .pa = Pattern.compile(StringReplace
230: .toJavaPattern(this .pattern));
231: pattern2prop.put(pa, this );
232: } else {
233: this .pa = null;
234: }
235: } else {
236: this .prefix = null;
237: this .pattern = null;
238: this .patternOnField = false;
239: this .patternIsRegExp = false;
240: this .pa = null;
241: this .cpm = null;
242: if (idx1 == -1 && idx2 == -1) {
243: //no pattern and no prefix
244: } else if (idx1 >= idx2 && logger != null) {
245: logger.log(BasicLevel.WARN, "Property '" + name
246: + "' is malformed");
247: }
248: }
249: }
250:
251: public boolean match(String path) {
252: boolean match = patternIsRegExp
253: && pa.matcher(path).matches();
254: if (match && logger != null
255: && logger.isLoggable(BasicLevel.DEBUG)) {
256: logger.log(BasicLevel.DEBUG, "Property '" + name
257: + "' matches the pattern '" + path
258: + "', value=" + value);
259: }
260: return match;
261: }
262:
263: public void applyProperty(HomeItf sh) {
264: if (cpm == null) {
265: cpm = (ClassPropertyManager) prefix2Impl.get(prefix);
266: }
267: if (cpm == null) {
268: logger.log(BasicLevel.WARN,
269: "Cannot apply the property '" + name + "' to '"
270: + sh.getPath() + "': " + "\n\tprefix= "
271: + prefix + "\nprefix2Impl="
272: + prefix2Impl);
273: } else {
274: cpm.applyProperty(name, value, sh, speedoProperties,
275: logger);
276: }
277: }
278:
279: public void applyProperty(HomeItf gcHome, HomeItf refHome) {
280: if (cpm == null) {
281: cpm = (ClassPropertyManager) prefix2Impl.get(prefix);
282: }
283: if (cpm == null) {
284: logger.log(BasicLevel.WARN,
285: "Cannot apply the property '" + name + "' to '"
286: + gcHome.getPath() + "'.");
287: } else {
288: cpm.applyProperty(name, value, gcHome, refHome,
289: speedoProperties, logger);
290: }
291: }
292: }
293:
294: /**
295: * Applies a property on known persistent classes
296: * @param prop is the property to apply
297: * @param classNames is the list of known persistent classes
298: */
299: private void applyProperty(final Prop prop,
300: final String[] classNames) {
301: if (prop.pattern != null) {
302: return;
303: }
304: //Iterator over each konwn class to apply property if the pattern match
305: for (int i = 0; i < classNames.length; i++) {
306: if (prop.patternOnField) {
307: //Fetch list of fields belong the class
308: HomeItf sh = (HomeItf) mapper.lookup(classNames[i]);
309: //TODO: provide in HomeItf (PClassMapping maybe) a new method
310: // returning the list of persistent field.
311: String[] fieldNames = new String[0]; //sh.get ...
312: for (int j = 0; j < fieldNames.length; j++) {
313: //build the path from the class name and the field name
314: String path = classNames[i] + FIELD_SEP
315: + fieldNames[j];
316: if (prop.match(path)) {
317: //The path matches
318: HomeItf subHome;
319: try {
320: //Try to find the home of the gen clas if the field
321: // corresponds to a genclass reference
322: subHome = (HomeItf) sh
323: .getGenClassMapping(fieldNames[i]);
324: } catch (UnsupportedOperationException e) {
325: //The field is not a reference to gen class
326: subHome = sh;
327: }
328: //apply the property on the home
329: prop.applyProperty(subHome);
330: }
331: }
332: } else if (prop.match(classNames[i])) {
333: //the property is not for a field and matches to the class name
334: String path = classNames[i];
335: //find the home corresponding to the class name
336: HomeItf sh = (HomeItf) mapper.lookup(path);
337: //apply the property on the home
338: prop.applyProperty(sh);
339: }
340: }
341: }
342: }
|