org.netbeans.modules.schema2beans.DDParser Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.schema2beans;
import java.util.*;
import java.io.*;
/**
* This class provides an implementation of the Iterator interface.
*
* Providing a parsing string (/prop1/prop2/...), the iterator parses
* the specified BaseBean, searching for the specified properties.
* As the hasMore()/next() methods are called, the parser goes over
* all the instances of the BaseBean tree.
*
* For example, assuming we have: /Book/Chapters/Title, the iterator
* would return all the titles of all the Chapters of the book.
*
* The iterator always returns elements of the type specified as the
* last element of the parsing string. In the above example, the
* parser would return only Title elements.
*
* If the parsing string is /EnterpriseBean/Entity, the parser would
* return all the Entity beans of the tree. Therefore, the type returned
* can be either a BaseBean or a final property type. Note that in case
* of a final property value, only objects are returned. Scalar types
* are wrapped using the appropriate class (int/Integer, ...).
*
* TODO: support for attributes, keys and limited arrays (only first
* element for example).
*
*/
public class DDParser implements Iterator {
public static class DDLocation {
BaseBean root;
String name;
int index;
int type;
public DDLocation(BaseBean r) {
this(r, null, -1, 0);
}
public DDLocation(BaseBean r, String n, int i, int type) {
this.root = r;
this.name = n;
if (i != -1) {
// This gets the internal index value that doesn't change
// even when an element of the array is removed
this.index = r.indexToId(n, i);
} else
this.index = i;
this.type = type;
}
public void removeValue() {
if (this.index != -1) {
this.root.removeValue(this.name,
this.root.getValueById(this.name,
this.index));
}
else
this.root.setValue(this.name, null);
}
public void setValue(String value) {
Object v = value;
if (Common.isBoolean(this.type))
v = Boolean.valueOf(value);
if (this.index != -1)
this.root.setValueById(this.name, this.index, v);
else
this.root.setValue(this.name, v);
}
public Object getValue() {
if (this.root == null || this.name == null)
return null;
if (this.index != -1)
return this.root.getValueById(this.name, this.index);
else
return this.root.getValue(this.name);
}
public BaseBean getRoot() {
return this.root;
}
public String getName() {
return this.name;
}
public int getIndex() {
if (this.name != null)
return this.root.idToIndex(this.name, this.index);
return this.index;
}
public boolean isNode() {
return Common.isBean(this.type);
}
public String toString() { // BEGIN_NOI18N
if (this.root != null) {
return "BaseBean(" + this.root.name() + "." +
Integer.toHexString(this.root.hashCode()) + ") " +
this.name + "[" +
((this.name==null)?"i"+this.index:
""+this.root.idToIndex(this.name, this.index)) +
"] - isNode: " +
this.isNode();
} else {
return "BaseBean(null)";
}
} // END_NOI18N
}
/**
* There is one such class per property specified in the parsing string.
* For example, if the parsing string is /Book/Chapters/Title,
* we would have three instances of the PropParser class. One for Book,
* one Chapters and another one for Title. Furthermore, the PropParser
* instances would be linked to each other through the parent/child
* attributes (Book.parent = null, Book.child = Chapters, ...)
*
* This class really implements the Iterator logic, using a bottom/up
* algorithm: the DDParser.next() always asks for the element of the
* last PropParser (the one with child = null). Then this element
* either return what's available, either asks for its next parent
* in order to get new values. Its parent, in turns might asks for
* new values to its parents, and so on, until the root is reached and
* nothing else is available.
*/
static class PropParser {
String name;
int pos;
Object[] values;
BaseProperty baseProp;
PropParser parent;
PropParser child;
Object cache;
boolean hasCache;
BaseBean curParent;
String keyName;
String keyValue;
boolean autoCreate;
PropParser(String n, boolean autoCreate) {
int i = n.indexOf('=');
if (i != -1) {
int j = n.indexOf('.');
if (j != -1 && j < i) {
this.name = n.substring(0, j);
this.keyName = n.substring(j+1, i);
this.keyValue = n.substring(i+1);
} else {
this.name = n.substring(0, i);
this.keyName = null;
this.keyValue = n.substring(i+1);
}
} else {
if(n.indexOf('.') != -1) {
throw new IllegalStateException(Common.getMessage(
"DDParserCannotUseKeyWithOutValue_msg", n));
}
this.name = n;
this.keyName = null;
this.keyValue = null;
}
if (this.keyValue != null && (this.keyValue.length() > 0) &&
(this.keyValue.charAt(0) == '\'' ||
this.keyValue.charAt(0) == '"')) { // NOI18N
this.keyValue =
this.keyValue.substring(1, this.keyValue.length()-1);
}
this.autoCreate = autoCreate;
this.parent = null;
this.pos = 0;
this.cache = null;
this.parent = null;
this.child = null;
this.hasCache = false;
this.curParent = null;
}
DDLocation getLocation() {
return new DDParser.DDLocation(this.curParent, this.name,
((this.baseProp.isIndexed())?
this.pos-1:-1),
((BeanProp)this.baseProp).getType());
}
void setBaseProperty(BaseProperty bp) {
this.baseProp = bp;
}
BaseBean getCurBaseBean(boolean lastProp) {
while(true) {
int p = this.seekNext();
if (p != -1) {
// Pos for the next one if intermediate
if (!lastProp)
this.pos++;
return (BaseBean)this.values[p];
}
try {
if (!this.updateValues())
break;
} catch(NoSuchElementException e) {
break;
}
}
return null;
}
int seekNext() {
// Seek doesn't move the pos - next() does
if (this.baseProp.isBean()) {
while(this.values.length>this.pos
&& this.values[this.pos] == null) {
this.pos++;
}
}
if (this.values.length == this.pos)
return -1;
return this.pos;
}
static final char WILD_CHAR = '*';
private boolean checkValueMatch(Object o1, Object o2) {
if (o1 == null || o2 == null) {
return false;
} else {
String s1 = o1.toString();
String s2 = o2.toString();
if (s1.charAt(0) == WILD_CHAR) {
return s2.endsWith(s1.substring(1));
} else
if (s1.charAt(s1.length()-1) == WILD_CHAR) {
return s2.startsWith(s1.substring(0, s1.length()-1));
} else {
return s1.equals(s2);
}
}
}
// BaseBean is the parent - get our values from it
void setValues(BaseBean b) {
this.curParent = b;
if (baseProp.isIndexed()) {
this.values = b.getValues(this.name);
} else {
this.values = new Object[1];
this.values[0] = b.getValue(this.name);
}
// If any keyName/keyValue is used, apply it to the values
if (this.baseProp.isBean()) {
if (this.keyName != null && this.keyValue != null) {
ArrayList arr = new ArrayList();
Object o1 = Common.getComparableObject(this.keyValue);
for (int i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy