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     */
017    package org.apache.commons.jxpath.ri.model.beans;
018    
019    import java.util.Locale;
020    
021    import org.apache.commons.jxpath.JXPathBeanInfo;
022    import org.apache.commons.jxpath.JXPathIntrospector;
023    import org.apache.commons.jxpath.ri.QName;
024    import 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 15:10:38 -0500 (Mon, 23 Jun 2008) $
034     */
035    public 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    }