001: /*
002: * Copyright 2006 JBoss Inc
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://www.apache.org/licenses/LICENSE-2.0
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.lang.dsl;
018:
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.regex.Matcher;
025: import java.util.regex.Pattern;
026:
027: /**
028: * A default implementation for the DSL Mapping Entry interface
029: *
030: * @author etirelli
031: */
032: public class DefaultDSLMappingEntry implements DSLMappingEntry {
033:
034: private Section section;
035: private MetaData metadata;
036: private String key;
037: private String value;
038:
039: private Map variables = Collections.EMPTY_MAP;
040:
041: private Pattern keyPattern;
042: private String valuePattern;
043:
044: // following pattern is used to extract all variables names and positions from a mapping.
045: // Example: for the following String:
046: //
047: // {This} is a {pattern} considered pretty \{{easy}\} by most \{people\}. What do you {say}
048: //
049: // it will return variables:
050: // This, pattern, easy, say
051: //
052: static final Pattern varFinder = Pattern.compile(
053: "(^|[^\\\\])\\{([(\\\\\\{)|[^\\{]]*?)\\}",
054: Pattern.MULTILINE | Pattern.DOTALL);
055:
056: public DefaultDSLMappingEntry() {
057: this (DSLMappingEntry.ANY, DSLMappingEntry.EMPTY_METADATA, null,
058: null);
059: }
060:
061: public DefaultDSLMappingEntry(final Section section,
062: final MetaData metadata, final String key,
063: final String value) {
064: this .section = section;
065: this .metadata = metadata;
066: this .setMappingKey(key);
067: this .setMappingValue(value);
068: }
069:
070: /**
071: * @inheritDoc
072: */
073: public Section getSection() {
074: return this .section;
075: }
076:
077: /**
078: * @inheritDoc
079: */
080: public DSLMappingEntry.MetaData getMetaData() {
081: return this .metadata;
082: }
083:
084: /**
085: * @inheritDoc
086: */
087: public String getMappingKey() {
088: return this .key;
089: }
090:
091: /**
092: * @inheritDoc
093: */
094: public String getMappingValue() {
095: return this .value;
096: }
097:
098: /**
099: * @param key the key to set
100: */
101: public void setMappingKey(String key) {
102: if (key != null) {
103: key = key.trim();
104: }
105: this .key = key;
106:
107: if (key != null) {
108: int substr = 0;
109: // escape '$' to avoid errors
110: final Matcher m = varFinder.matcher(key.replaceAll("\\$",
111: "\\\\\\$"));
112: // retrieving variables list and creating key pattern
113: final StringBuffer buf = new StringBuffer();
114:
115: int counter = 1;
116: if (!key.startsWith("^")) {
117: // making it start with a space char or a line start
118: buf.append("(\\W|^)");
119: substr += buf.length();
120: counter++;
121: }
122:
123: while (m.find()) {
124: if (this .variables == Collections.EMPTY_MAP) {
125: this .variables = new HashMap(2);
126: }
127: this .variables.put(m.group(2), new Integer(counter++));
128: m.appendReplacement(buf, m.group(1) + "(.*?)");
129: }
130: m.appendTail(buf);
131:
132: // if pattern ends with a variable, append a line end to avoid multiple line matching
133: if (buf.toString().endsWith("(.*?)")) {
134: buf.append("$");
135: } else {
136: buf.append("(\\W|$)");
137: }
138:
139: // setting the key pattern and making it space insensitive
140: String pat = buf.toString();
141: if (pat.substring(substr).trim().startsWith("-")
142: && (!pat.substring(substr).trim().startsWith(
143: "-\\s*"))) {
144: pat = pat.substring(0, pat.indexOf('-') + 1) + "\\s*"
145: + pat.substring(pat.indexOf('-') + 1).trim();
146: }
147: pat = pat.replaceAll("\\s+", "\\\\s+");
148: this .keyPattern = Pattern.compile(pat, Pattern.DOTALL
149: | Pattern.MULTILINE);
150:
151: } else {
152: this .keyPattern = null;
153: }
154: // update value mapping
155: this .setMappingValue(this .value);
156: }
157:
158: /**
159: * @param section the section to set
160: */
161: public void setSection(final Section section) {
162: this .section = section;
163: }
164:
165: /**
166: * @param value the value to set
167: */
168: public void setMappingValue(final String value) {
169: this .valuePattern = value;
170: this .value = value;
171: if (value != null) {
172: this .valuePattern = this .valuePattern.replaceAll("\\\\n",
173: "\n").replaceAll("\\$", "\\\\\\$");
174: for (final Iterator it = this .variables.entrySet()
175: .iterator(); it.hasNext();) {
176: final Map.Entry entry = (Map.Entry) it.next();
177: final String var = (String) entry.getKey();
178: final int pos = ((Integer) entry.getValue()).intValue();
179:
180: this .valuePattern = this .valuePattern.replaceAll("\\{"
181: + var + "\\}", "\\$" + pos);
182: }
183: }
184: }
185:
186: /**
187: * @param metadata the metadata to set
188: */
189: public void setMetaData(final MetaData metadata) {
190: this .metadata = metadata;
191: }
192:
193: /**
194: * @return the keyPattern
195: */
196: public Pattern getKeyPattern() {
197: return this .keyPattern;
198: }
199:
200: /**
201: * @return the valuePattern
202: */
203: public String getValuePattern() {
204: return this .valuePattern;
205: }
206:
207: /**
208: * @return the variables
209: */
210: public Map getVariables() {
211: return this .variables;
212: }
213:
214: public String toPatternString() {
215: return this .section + "[" + this .metadata + "]"
216: + this .keyPattern.pattern() + "=" + this .valuePattern;
217: }
218:
219: public String toString() {
220: return this .section + "[" + this .metadata + "]" + this .key
221: + "=" + this .value;
222: }
223:
224: /* (non-Javadoc)
225: * @see java.lang.Object#hashCode()
226: */
227: public int hashCode() {
228: final int PRIME = 31;
229: int result = 1;
230: result = PRIME * result
231: + ((this .key == null) ? 0 : this .key.hashCode());
232: result = PRIME
233: * result
234: + ((this .metadata == null) ? 0 : this .metadata
235: .hashCode());
236: result = PRIME
237: * result
238: + ((this .section == null) ? 0 : this .section.hashCode());
239: result = PRIME * result
240: + ((this .value == null) ? 0 : this .value.hashCode());
241: return result;
242: }
243:
244: /* (non-Javadoc)
245: * @see java.lang.Object#equals(java.lang.Object)
246: */
247: public boolean equals(final Object obj) {
248: if (this == obj) {
249: return true;
250: }
251: if (obj == null) {
252: return false;
253: }
254: if (getClass() != obj.getClass()) {
255: return false;
256: }
257: final DefaultDSLMappingEntry other = (DefaultDSLMappingEntry) obj;
258: if (this .key == null) {
259: if (other.key != null) {
260: return false;
261: }
262: } else if (!this .key.equals(other.key)) {
263: return false;
264: }
265: if (this .metadata == null) {
266: if (other.metadata != null) {
267: return false;
268: }
269: } else if (!this .metadata.equals(other.metadata)) {
270: return false;
271: }
272: if (this .section == null) {
273: if (other.section != null) {
274: return false;
275: }
276: } else if (!this .section.equals(other.section)) {
277: return false;
278: }
279: if (this .value == null) {
280: if (other.value != null) {
281: return false;
282: }
283: } else if (!this .value.equals(other.value)) {
284: return false;
285: }
286: return true;
287: }
288:
289: public List getErrors() {
290: // TODO Need to implement validation here
291: return Collections.EMPTY_LIST;
292: }
293:
294: }
|