All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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