001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.jxpath.ri.model.beans;
018
019import java.util.Locale;
020
021import org.apache.commons.jxpath.JXPathBeanInfo;
022import org.apache.commons.jxpath.JXPathIntrospector;
023import org.apache.commons.jxpath.ri.QName;
024import org.apache.commons.jxpath.ri.model.NodePointer;
025
026/**
027 * A Pointer that points to a JavaBean or a collection. It is either
028 * the first element of a path or a pointer for a property value.
029 * Typically there is a {@link BeanPropertyPointer} between two BeanPointers
030 * in the chain.
031 *
032 * @author Dmitri Plotnikov
033 * @version $Revision: 670727 $ $Date: 2008-06-23 22:10:38 +0200 (Mo, 23 Jun 2008) $
034 */
035public class BeanPointer extends PropertyOwnerPointer {
036    private QName name;
037    private Object bean;
038    private JXPathBeanInfo beanInfo;
039
040    private static final long serialVersionUID = -8227317938284982440L;
041
042    /**
043     * Create a new BeanPointer.
044     * @param name is the name given to the first node
045     * @param bean pointed
046     * @param beanInfo JXPathBeanInfo
047     * @param locale Locale
048     */
049    public BeanPointer(QName name, Object bean, JXPathBeanInfo beanInfo,
050            Locale locale) {
051        super(null, locale);
052        this.name = name;
053        this.bean = bean;
054        this.beanInfo = beanInfo;
055    }
056
057    /**
058     * Create a new BeanPointer.
059     * @param parent pointer
060     * @param name is the name given to the first node
061     * @param bean pointed
062     * @param beanInfo JXPathBeanInfo
063     */
064    public BeanPointer(NodePointer parent, QName name, Object bean,
065            JXPathBeanInfo beanInfo) {
066        super(parent);
067        this.name = name;
068        this.bean = bean;
069        this.beanInfo = beanInfo;
070    }
071
072    public PropertyPointer getPropertyPointer() {
073        return new BeanPropertyPointer(this, beanInfo);
074    }
075
076    public QName getName() {
077        return name;
078    }
079
080    public Object getBaseValue() {
081        return bean;
082    }
083
084    /**
085     * {@inheritDoc}
086     * @return false
087     */
088    public boolean isCollection() {
089        return false;
090    }
091
092    /**
093     * {@inheritDoc}
094     * @return 1
095     */
096    public int getLength() {
097        return 1;
098    }
099
100    public boolean isLeaf() {
101        Object value = getNode();
102        return value == null
103            || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
104    }
105
106    public int hashCode() {
107        return name == null ? 0 : name.hashCode();
108    }
109
110    public boolean equals(Object object) {
111        if (object == this) {
112            return true;
113        }
114
115        if (!(object instanceof BeanPointer)) {
116            return false;
117        }
118
119        BeanPointer other = (BeanPointer) object;
120        if (parent != other.parent && (parent == null || !parent.equals(other.parent))) {
121            return false;
122        }
123
124        if ((name == null && other.name != null)
125                || (name != null && !name.equals(other.name))) {
126            return false;
127        }
128
129        int iThis = (index == WHOLE_COLLECTION ? 0 : index);
130        int iOther = (other.index == WHOLE_COLLECTION ? 0 : other.index);
131        if (iThis != iOther) {
132            return false;
133        }
134
135        if (bean instanceof Number
136                || bean instanceof String
137                || bean instanceof Boolean) {
138            return bean.equals(other.bean);
139        }
140        return bean == other.bean;
141    }
142
143    /**
144     * {@inheritDoc}
145     * If the pointer has a parent, then parent's path.
146     * If the bean is null, "null()".
147     * If the bean is a primitive value, the value itself.
148     * Otherwise - an empty string.
149     */
150    public String asPath() {
151        if (parent != null) {
152            return super.asPath();
153        }
154        if (bean == null) {
155            return "null()";
156        }
157        if (bean instanceof Number) {
158            String string = bean.toString();
159            if (string.endsWith(".0")) {
160                string = string.substring(0, string.length() - 2);
161            }
162            return string;
163        }
164        if (bean instanceof Boolean) {
165            return ((Boolean) bean).booleanValue() ? "true()" : "false()";
166        }
167        if (bean instanceof String) {
168            return "'" + bean + "'";
169        }
170        return "/";
171    }
172}