org.getobjects.rules.RuleParser.java Source code

Java tutorial

Introduction

Here is the source code for org.getobjects.rules.RuleParser.java

Source

/*
  Copyright (C) 2006 Helge Hess
    
  This file is part of Go.
    
  Go is free software; you can redistribute it and/or modify it under
  the terms of the GNU Lesser General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.
    
  Go is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  License for more details.
    
  You should have received a copy of the GNU Lesser General Public
  License along with Go; see the file COPYING.  If not, write to the
  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  02111-1307, USA.
*/

package org.getobjects.rules;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.getobjects.eocontrol.EOBooleanQualifier;
import org.getobjects.eocontrol.EOQualifier;
import org.getobjects.eocontrol.EOQualifierParser;
import org.getobjects.foundation.NSClassLookupContext;
import org.getobjects.foundation.NSJavaRuntime;
import org.getobjects.foundation.NSObject;
import org.getobjects.foundation.NSPropertyListParser;
import org.getobjects.foundation.UObject;
import org.getobjects.foundation.UString;

// TODO: properly report errors in last-exception!
// TODO: improve performance
// TODO: parse assignment class? (eg "a = b; (BoolAssignment)")

public class RuleParser extends NSObject {
    protected static Log log = LogFactory.getLog("GoRuleParser");

    public static int RULE_PRIORITY_IMPORTANT = 1000;
    public static int RULE_PRIORITY_VERYHIGH = 200;
    public static int RULE_PRIORITY_HIGH = 150;
    public static int RULE_PRIORITY_NORMAL = 100;
    public static int RULE_PRIORITY_LOW = 50;
    public static int RULE_PRIORITY_VERYLOW = 5;
    public static int RULE_PRIORITY_FALLBACK = 0;

    protected NSClassLookupContext classLookup;

    public RuleParser(NSClassLookupContext _clslookup) {
        this.classLookup = _clslookup;
    }

    public RuleParser() {
        this(NSClassLookupContext.NSSystemClassLookupContext);
    }

    /* parsing */

    public Rule parseRule(String _s) {
        if (_s == null || _s.length() == 0)
            return null;

        int idx = UString.indexOfStringBySkippingQuotes(_s, "=>", "\"'", '\\');
        if (idx < 3) {
            log.info("could not parse rule: '" + _s + "'");
            return null;
        }

        /* parse qualifier */

        EOQualifier q = this.parseQualifier(_s.substring(0, idx).trim());
        if (q == null) {
            log.info("could not parse qualifier of rule: '" + _s + "'");
            return null;
        }

        /* scan for priority separator */

        String remainder = _s.substring(idx + 2);
        idx = UString.indexOfStringBySkippingQuotes(remainder, ";", "\"", '\\');

        /* parse priority */

        int priority = RULE_PRIORITY_NORMAL;
        if (idx != -1)
            priority = parsePriority(remainder.substring(idx + 1).trim());

        /* parse action / assignment */

        Object action = this.parseAction(remainder.substring(0, idx), null /*cls*/);
        if (action == null) {
            log.info("could not parse action of rule: '" + _s + "'");
            return null;
        }

        /* return rule */
        return new Rule(q, action, priority);
    }

    public EOQualifier parseQualifier(String _s) {
        if (_s == null || _s.length() == 0)
            return null;

        if ("*true*".equals(_s))
            return EOBooleanQualifier.trueQualifier;
        if ("*false*".equals(_s))
            return EOBooleanQualifier.falseQualifier;

        EOQualifierParser p = new EOQualifierParser(_s.toCharArray(), null /* args */);

        return p.parseQualifier();
    }

    public static int parsePriority(String _s) {
        if (_s == null || _s.length() == 0)
            return RULE_PRIORITY_NORMAL;

        char c0 = _s.charAt(0);
        if (Character.isDigit(c0) || c0 == '-')
            return UObject.intValue(_s);

        if ("important".equals(_s))
            return RULE_PRIORITY_IMPORTANT;
        if ("very high".equals(_s))
            return RULE_PRIORITY_VERYHIGH;
        if ("high".equals(_s))
            return RULE_PRIORITY_HIGH;
        if ("normal".equals(_s))
            return RULE_PRIORITY_NORMAL;
        if ("default".equals(_s))
            return RULE_PRIORITY_NORMAL;
        if ("low".equals(_s))
            return RULE_PRIORITY_LOW;
        if ("very low".equals(_s))
            return RULE_PRIORITY_VERYLOW;
        if ("fallback".equals(_s))
            return RULE_PRIORITY_FALLBACK;

        log.warn("unknown rule priority: '" + _s + "'");
        return RULE_PRIORITY_NORMAL;
    }

    protected static final Class[] AssiCtorSig = { String.class, Object.class };

    public Object parseAction(String _s, String _forceClassName) {
        if (_s == null || _s.length() == 0)
            return null;

        Class enforcedClass = null;
        if (_s.charAt(0) == '(') {
            // TODO: parse an Assignment type cast
            int sidx = _s.indexOf(')');
            if (sidx == -1)
                log.error("typecast is not closed: " + _s);
            else {
                String clsname = _s.substring(1, sidx);
                enforcedClass = this.classLookup.lookupClass(clsname);
            }
        } else if (_forceClassName != null)
            enforcedClass = this.classLookup.lookupClass(_forceClassName);

        int idx = UString.indexOfStringBySkippingQuotes(_s, "=", "\"'", '\\');
        if (idx < 1) {
            log.info("could not parse assignment: '" + _s + "'");
            return null;
        }

        String key = _s.substring(0, idx).trim();
        String valstr = _s.substring(idx + 1).trim();

        Class assignmentClass = enforcedClass != null ? enforcedClass : RuleKeyAssignment.class;
        Object value = valstr;

        /* parse value */

        if (enforcedClass == null && valstr.length() > 0) {
            char c0 = valstr.charAt(0);

            if (c0 == '"' || c0 == '\'') { /* quoted string */
                if (valstr.charAt(valstr.length() - 1) != c0) {
                    log.error("string value of assignment misses a closing quote");
                    value = valstr.substring(1);
                } else
                    value = valstr.subSequence(1, valstr.length() - 1);
            } else if (Character.isDigit(c0) || c0 == '-') { /* number */
                value = UObject.intValue(valstr);
            } else if (c0 == '{' || c0 == '(') { /* property list */
                NSPropertyListParser p = new NSPropertyListParser();
                value = p.parse(valstr);
                if (value == null)
                    log.error("could not parse plist of assignment: " + valstr);
            } else {
                if (valstr.equals("true"))
                    value = Boolean.TRUE;
                else if (valstr.equals("false"))
                    value = Boolean.FALSE;
                else if (valstr.equals("YES"))
                    value = Boolean.TRUE;
                else if (valstr.equals("NO"))
                    value = Boolean.FALSE;
                else if (valstr.equals("null"))
                    value = null;
                else if (valstr.equals("nil"))
                    value = null;
            }

            if (value != valstr)
                assignmentClass = RuleAssignment.class;
        }

        /* construct */

        return NSJavaRuntime.NSAllocateObject(assignmentClass, AssiCtorSig, new Object[] { key, value });
    }
}