001: /*
002: * Copyright 2002-2005 Peter Lin & RuleML.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://ruleml-dev.sourceforge.net/
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: *
016: */
017: package org.drools.facttemplates;
018:
019: import java.util.Arrays;
020:
021: import org.drools.rule.Package;
022:
023: /**
024: * @author Peter Lin
025: * Deftemplate is equivalent to CLIPS deftemplate<br/>
026: *
027: * Some general design notes about the current implementation. In the
028: * case where a class is declared to create the deftemplate, the order
029: * of the slots are based on java Introspection. In the case where an
030: * user declares the deftemplate from console or directly, the order
031: * is the same as the string equivalent.
032: * The current implementation does not address redeclaring a deftemplate
033: * for a couple of reasons. The primary one is how does it affect the
034: * existing RETE nodes. One possible approach is to always add new slots
035: * to the end of the deftemplate and ignore the explicit order. Another
036: * is to recompute the deftemplate, binds and all nodes. The second
037: * approach is very costly and would make redeclaring a deftemplate
038: * undesirable.
039: */
040: public class FactTemplateImpl implements FactTemplate {
041: private static int hashCode(final Object[] array) {
042: final int PRIME = 31;
043: if (array == null) {
044: return 0;
045: }
046: int result = 1;
047: for (int index = 0; index < array.length; index++) {
048: result = PRIME
049: * result
050: + (array[index] == null ? 0 : array[index]
051: .hashCode());
052: }
053: return result;
054: }
055:
056: private FieldTemplate[] fields;
057: private Package pkg;
058: private String name;
059:
060: public FactTemplateImpl(final Package pkg, final String name,
061: final FieldTemplate[] fields) {
062: this .pkg = pkg;
063: this .name = name;
064: this .fields = fields;
065: this .pkg.addFactTemplate(this );
066: }
067:
068: public Package getPackage() {
069: return this .pkg;
070: }
071:
072: /**
073: * the template name is an alias for an object
074: * @param name
075: */
076: public String getName() {
077: return this .name;
078: }
079:
080: /**
081: * Return the number of slots in the deftemplate
082: * @return
083: */
084: public int getNumberOfFields() {
085: return this .fields.length;
086: }
087:
088: /**
089: * Return all the slots
090: * @return
091: */
092: public FieldTemplate[] getAllFieldTemplates() {
093: return this .fields;
094: }
095:
096: /**
097: * A convienance method for finding the slot matching
098: * the String name.
099: * @param name
100: * @return
101: */
102: public FieldTemplate getFieldTemplate(final String name) {
103: for (int idx = 0; idx < this .fields.length; idx++) {
104: if (this .fields[idx].getName().equals(name)) {
105: return this .fields[idx];
106: }
107: }
108: return null;
109: }
110:
111: /**
112: * get the Slot at the given pattern id
113: * @param id
114: * @return
115: */
116: public FieldTemplate getFieldTemplate(final int index) {
117: return this .fields[index];
118: }
119:
120: /**
121: * Look up the pattern index of the slot
122: * @param name
123: * @return
124: */
125: public int getFieldTemplateIndex(final String name) {
126: for (int index = 0; index < this .fields.length; index++) {
127: if (this .fields[index].getName().equals(name)) {
128: return index;
129: }
130: }
131: return -1;
132: }
133:
134: /**
135: * Method takes a list of Slots and creates a deffact from it.
136: * @param data
137: * @param id
138: * @return
139: */
140: public Fact createFact(final long id) {
141: return new FactImpl(this , id);
142: }
143:
144: /**
145: * Method will return a string format with the int type code
146: * for the slot type
147: */
148: public String toString() {
149: final StringBuffer buf = new StringBuffer();
150: buf.append("(" + this .name + " ");
151: // for (int idx=0; idx < this.slots.length; idx++){
152: // buf.append("(" + this.slots[idx].getName() +
153: // " (type " + ConversionUtils.getTypeName(
154: // this.slots[idx].getValueType()) +
155: // ") ) ");
156: // }
157: // if (this.clazz != null){
158: // buf.append("[" + this.clazz.getClassObject().getName() + "] ");
159: // }
160: buf.append(")");
161: return buf.toString();
162: }
163:
164: public int hashCode() {
165: final int PRIME = 31;
166: int result = 1;
167: result = PRIME * result
168: + FactTemplateImpl.hashCode(this .fields);
169: result = PRIME * result + this .name.hashCode();
170: result = PRIME * result + this .pkg.hashCode();
171: return result;
172: }
173:
174: public boolean equals(final Object object) {
175: if (this == object) {
176: return true;
177: }
178:
179: if (object == null || getClass() != object.getClass()) {
180: return false;
181: }
182:
183: final FactTemplateImpl other = (FactTemplateImpl) object;
184: if (!Arrays.equals(this .fields, other.fields)) {
185: return false;
186: }
187:
188: return this.pkg.equals(other.pkg)
189: && this.name.equals(other.name);
190: }
191:
192: }
|