001: /*
002: * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003: *
004: * http://izpack.org/
005: * http://izpack.codehaus.org/
006: *
007: * Copyright 2007 Dennis Reil
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: */
021: package com.izforge.izpack.rules;
022:
023: import com.izforge.izpack.Pack;
024: import com.izforge.izpack.installer.InstallData;
025: import com.izforge.izpack.util.Debug;
026: import net.n3.nanoxml.XMLElement;
027:
028: import java.util.*;
029:
030: /**
031: * The rules engine class is the central point for checking conditions
032: *
033: * @author Dennis Reil, <Dennis.Reil@reddot.de> created: 09.11.2006, 13:48:39
034: */
035: public class RulesEngine {
036:
037: protected Map<String, String> panelconditions;
038:
039: protected Map<String, String> packconditions;
040:
041: protected Map<String, String> optionalpackconditions;
042:
043: protected XMLElement conditionsspec;
044:
045: protected static Map conditionsmap = new Hashtable();
046:
047: protected static InstallData installdata;
048:
049: private RulesEngine() {
050: conditionsmap = new Hashtable();
051: this .panelconditions = new Hashtable<String, String>();
052: this .packconditions = new Hashtable<String, String>();
053: this .optionalpackconditions = new Hashtable<String, String>();
054: }
055:
056: /**
057: * initializes builtin conditions
058: */
059: private void init() {
060: createBuiltinOsCondition("IS_WINDOWS", "izpack.windowsinstall");
061: createBuiltinOsCondition("IS_LINUX", "izpack.linuxinstall");
062: createBuiltinOsCondition("IS_SUNOS", "izpack.solarisinstall");
063: createBuiltinOsCondition("IS_MAC", "izpack.macinstall");
064: createBuiltinOsCondition("IS_SUNOS", "izpack.solarisinstall");
065: createBuiltinOsCondition("IS_SUNOS_X86",
066: "izpack.solarisinstall.x86");
067: createBuiltinOsCondition("IS_SUNOS_SPARC",
068: "izpack.solarisinstall.sparc");
069:
070: if ((installdata != null) && (installdata.allPacks != null)) {
071: for (Pack pack : installdata.allPacks) {
072: if (pack.id != null) {
073: // automatically add packselection condition
074: PackselectionCondition packselcond = new PackselectionCondition();
075: packselcond.setInstalldata(installdata);
076: packselcond.id = "izpack.selected." + pack.id;
077: packselcond.packid = pack.id;
078: conditionsmap.put(packselcond.id, packselcond);
079: }
080: }
081: }
082: }
083:
084: private void createBuiltinOsCondition(String osVersionField,
085: String conditionId) {
086: JavaCondition condition = new JavaCondition();
087: condition.setInstalldata(installdata);
088: condition.id = conditionId;
089: condition.classname = "com.izforge.izpack.util.OsVersion";
090: condition.fieldname = osVersionField;
091: condition.returnvalue = "true";
092: condition.returnvaluetype = "boolean";
093: condition.complete = true;
094: conditionsmap.put(condition.id, condition);
095: }
096:
097: /**
098: *
099: */
100: public RulesEngine(XMLElement conditionsspecxml,
101: InstallData installdata) {
102: this ();
103: this .conditionsspec = conditionsspecxml;
104: RulesEngine.installdata = installdata;
105: this .readConditions();
106: init();
107: }
108:
109: public RulesEngine(Map rules, InstallData installdata) {
110: this ();
111: RulesEngine.installdata = installdata;
112: conditionsmap = rules;
113: Iterator keyiter = conditionsmap.keySet().iterator();
114: while (keyiter.hasNext()) {
115: String key = (String) keyiter.next();
116: Condition condition = (Condition) conditionsmap.get(key);
117: condition.setInstalldata(installdata);
118: }
119: init();
120: }
121:
122: /**
123: * Returns the current known condition ids.
124: *
125: * @return
126: */
127: public String[] getKnownConditionIds() {
128: String[] conditionids = (String[]) this .conditionsmap.keySet()
129: .toArray(new String[this .conditionsmap.size()]);
130: Arrays.sort(conditionids);
131: return conditionids;
132: }
133:
134: /**
135: * Checks if an attribute for an xmlelement is set.
136: *
137: * @param val value of attribute to check
138: * @param attribute the attribute which is checked
139: * @param element the element
140: * @return true value was set false no value was set
141: */
142: protected boolean checkAttribute(String val, String attribute,
143: String element) {
144: if ((val != null) && (val.length() > 0)) {
145: return true;
146: } else {
147: Debug.trace("Element " + element
148: + " has to specify an attribute " + attribute);
149: return false;
150: }
151: }
152:
153: public static Condition analyzeCondition(XMLElement condition) {
154: String condid = condition.getAttribute("id");
155: String condtype = condition.getAttribute("type");
156: Condition result = null;
157: if (condtype != null) {
158: String conditionclassname = "";
159: if (condtype.indexOf('.') > -1) {
160: conditionclassname = condtype;
161: } else {
162: String conditiontype = condtype.toLowerCase();
163: conditionclassname = "com.izforge.izpack.rules."
164: + conditiontype.substring(0, 1).toUpperCase()
165: + conditiontype.substring(1, conditiontype
166: .length());
167: conditionclassname += "Condition";
168: }
169: //ClassLoader loader = ClassLoader.getSystemClassLoader();
170: ClassLoader loader = RulesEngine.class.getClassLoader();
171: try {
172: Class<Condition> conditionclass = (Class<Condition>) loader
173: .loadClass(conditionclassname);
174: result = conditionclass.newInstance();
175: result.readFromXML(condition);
176: result.setId(condid);
177: result.setInstalldata(RulesEngine.installdata);
178: } catch (ClassNotFoundException e) {
179: Debug.trace(conditionclassname + " not found.");
180: } catch (InstantiationException e) {
181: Debug.trace(conditionclassname
182: + " couldn't be instantiated.");
183: } catch (IllegalAccessException e) {
184: Debug.trace("Illegal access to " + conditionclassname);
185: }
186: }
187: return result;
188: }
189:
190: /**
191: * Read the spec for the conditions
192: */
193: protected void readConditions() {
194: if (this .conditionsspec == null) {
195: Debug.trace("No specification for conditions found.");
196: return;
197: }
198: try {
199: if (this .conditionsspec.hasChildren()) {
200: // read in the condition specs
201: Vector<XMLElement> childs = this .conditionsspec
202: .getChildrenNamed("condition");
203:
204: for (XMLElement condition : childs) {
205: Condition cond = analyzeCondition(condition);
206: if (cond != null) {
207: // this.conditionslist.add(cond);
208: String condid = cond.getId();
209: cond.setInstalldata(RulesEngine.installdata);
210: if ((condid != null)
211: && !("UNKNOWN".equals(condid))) {
212: conditionsmap.put(condid, cond);
213: }
214: }
215: }
216:
217: Vector<XMLElement> panelconditionels = this .conditionsspec
218: .getChildrenNamed("panelcondition");
219: for (XMLElement panelel : panelconditionels) {
220: String panelid = panelel.getAttribute("panelid");
221: String conditionid = panelel
222: .getAttribute("conditionid");
223: this .panelconditions.put(panelid, conditionid);
224: }
225:
226: Vector<XMLElement> packconditionels = this .conditionsspec
227: .getChildrenNamed("packcondition");
228: for (XMLElement panelel : packconditionels) {
229: String panelid = panelel.getAttribute("packid");
230: String conditionid = panelel
231: .getAttribute("conditionid");
232: this .packconditions.put(panelid, conditionid);
233: // optional install allowed, if condition is not met?
234: String optional = panelel.getAttribute("optional");
235: if (optional != null) {
236: boolean optionalinstall = Boolean
237: .valueOf(optional);
238: if (optionalinstall) {
239: // optional installation is allowed
240: this .optionalpackconditions.put(panelid,
241: conditionid);
242: }
243: }
244: }
245: }
246: } catch (Exception e) {
247: e.printStackTrace();
248: }
249: }
250:
251: public static Condition getCondition(String id) {
252: Condition result = (Condition) conditionsmap.get(id);
253: if (result == null) {
254: result = getConditionByExpr(new StringBuffer(id));
255: }
256: return result;
257: }
258:
259: protected static Condition getConditionByExpr(
260: StringBuffer conditionexpr) {
261: Condition result = null;
262: int index = 0;
263: while (index < conditionexpr.length()) {
264: char currentchar = conditionexpr.charAt(index);
265: switch (currentchar) {
266: case '+':
267: // and-condition
268: Condition op1 = (Condition) conditionsmap
269: .get(conditionexpr.substring(0, index));
270: conditionexpr.delete(0, index + 1);
271: result = new AndCondition(op1,
272: getConditionByExpr(conditionexpr));
273: result.setInstalldata(RulesEngine.installdata);
274: break;
275: case '|':
276: // or-condition
277: op1 = (Condition) conditionsmap.get(conditionexpr
278: .substring(0, index));
279: conditionexpr.delete(0, index + 1);
280: result = new OrCondition(op1,
281: getConditionByExpr(conditionexpr));
282: result.setInstalldata(RulesEngine.installdata);
283: break;
284: case '\\':
285: // xor-condition
286: op1 = (Condition) conditionsmap.get(conditionexpr
287: .substring(0, index));
288: conditionexpr.delete(0, index + 1);
289: result = new XOrCondition(op1,
290: getConditionByExpr(conditionexpr));
291: result.setInstalldata(RulesEngine.installdata);
292: break;
293: case '!':
294: // not-condition
295: if (index > 0) {
296: Debug
297: .trace("error: ! operator only allowed at position 0");
298: } else {
299: // delete not symbol
300: conditionexpr.deleteCharAt(index);
301: result = new NotCondition(
302: getConditionByExpr(conditionexpr));
303: result.setInstalldata(RulesEngine.installdata);
304: }
305: break;
306: default:
307: // do nothing
308: }
309: index++;
310: }
311: if (conditionexpr.length() > 0) {
312: result = (Condition) conditionsmap.get(conditionexpr
313: .toString());
314: if (result != null) {
315: result.setInstalldata(RulesEngine.installdata);
316: conditionexpr.delete(0, conditionexpr.length());
317: }
318: }
319: return result;
320: }
321:
322: public boolean isConditionTrue(String id, Properties variables) {
323: Condition cond = getCondition(id);
324: if (cond == null) {
325: Debug.trace("Condition (" + id + ") not found.");
326: return true;
327: } else {
328: Debug.trace("Checking condition");
329: try {
330: return cond.isTrue();
331: } catch (NullPointerException npe) {
332: Debug.error("Nullpointerexception checking condition: "
333: + id);
334: return false;
335: }
336: }
337: }
338:
339: public boolean isConditionTrue(Condition cond, Properties variables) {
340: if (cond == null) {
341: Debug.trace("Condition not found.");
342: return true;
343: } else {
344: Debug.trace("Checking condition");
345: return cond.isTrue();
346: }
347: }
348:
349: public boolean isConditionTrue(String id) {
350: Condition cond = RulesEngine.getCondition(id);
351: if (cond != null) {
352: return this .isConditionTrue(cond);
353: } else {
354: return false;
355: }
356: }
357:
358: public boolean isConditionTrue(Condition cond) {
359: return cond.isTrue();
360: }
361:
362: /**
363: * Can a panel be shown?
364: *
365: * @param panelid - id of the panel, which should be shown
366: * @param variables - the variables
367: * @return true - there is no condition or condition is met false - there is a condition and the
368: * condition was not met
369: */
370: public boolean canShowPanel(String panelid, Properties variables) {
371: Debug.trace("can show panel with id " + panelid + " ?");
372: if (!this .panelconditions.containsKey(panelid)) {
373: Debug.trace("no condition, show panel");
374: return true;
375: }
376: Debug.trace("there is a condition");
377: Condition condition = getCondition(this .panelconditions
378: .get(panelid));
379: if (condition != null) {
380: return condition.isTrue();
381: }
382: return false;
383: }
384:
385: /**
386: * Is the installation of a pack possible?
387: *
388: * @param packid
389: * @param variables
390: * @return true - there is no condition or condition is met false - there is a condition and the
391: * condition was not met
392: */
393: public boolean canInstallPack(String packid, Properties variables) {
394: if (packid == null) {
395: return true;
396: }
397: Debug.trace("can install pack with id " + packid + "?");
398: if (!this .packconditions.containsKey(packid)) {
399: Debug.trace("no condition, can install pack");
400: return true;
401: }
402: Debug.trace("there is a condition");
403: Condition condition = getCondition(this .packconditions
404: .get(packid));
405: if (condition != null) {
406: return condition.isTrue();
407: }
408: return false;
409: }
410:
411: /**
412: * Is an optional installation of a pack possible if the condition is not met?
413: *
414: * @param packid
415: * @param variables
416: * @return
417: */
418: public boolean canInstallPackOptional(String packid,
419: Properties variables) {
420: Debug
421: .trace("can install pack optional with id " + packid
422: + "?");
423: if (!this .optionalpackconditions.containsKey(packid)) {
424: Debug.trace("not in optionalpackconditions.");
425: return false;
426: } else {
427: Debug.trace("optional install possible");
428: return true;
429: }
430: }
431: }
|