001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.util;
016    
017    import java.io.Serializable;
018    
019    import org.apache.hivemind.util.Defense;
020    import org.apache.tapestry.IComponent;
021    import org.apache.tapestry.INamespace;
022    import org.apache.tapestry.IPage;
023    import org.apache.tapestry.IRequestCycle;
024    
025    /**
026     * The ComponentAddress class contains the path to a component, allowing it to locate an instance of
027     * that component in a different {@link org.apache.tapestry.IRequestCycle}.
028     * <p>
029     * This class needs to be used mostly when working with components accessed via the
030     * {@link org.apache.tapestry.IRender}interface. It allows those components to serialize and pass
031     * as a service parameter information about what component they have to talk to if control returns
032     * back to them.
033     * <p>
034     * This situation often occurs when the component used via IRender contains Direct or Action links.
035     * 
036     * @author mindbridge
037     * @since 2.2
038     */
039    public class ComponentAddress implements Serializable
040    {
041        private static final long serialVersionUID = 533068199722072804L;
042    
043        private String _pageName;
044    
045        private String _idPath;
046    
047        /**
048         * Creates a new ComponentAddress object that carries the identification information of the
049         * given component (the page name and the ID path).
050         * 
051         * @param component
052         *            the component to get the address of
053         */
054        public ComponentAddress(IComponent component)
055        {
056            this(component.getPage().getPageName(), component.getIdPath());
057        }
058    
059        /**
060         * Creates a new ComponentAddress using the given Page Name and ID Path.
061         * 
062         * @param pageName
063         *            the name of the page that contains the component
064         * @param idPath
065         *            the ID Path of the component (which may be null)
066         */
067        public ComponentAddress(String pageName, String idPath)
068        {
069            Defense.notNull(pageName, "pageName");
070    
071            _pageName = pageName;
072            _idPath = idPath;
073        }
074    
075        /**
076         * Creates a new ComponentAddress using the given Page Name and ID Path relative on the provided
077         * Namespace.
078         * 
079         * @param namespace
080         *            the namespace of the page that contains the component
081         * @param pageName
082         *            the name of the page that contains the component
083         * @param idPath
084         *            the ID Path of the component
085         */
086        public ComponentAddress(INamespace namespace, String pageName, String idPath)
087        {
088            this(namespace.constructQualifiedName(pageName), idPath);
089        }
090    
091        /**
092         * Finds a component with the current address using the given RequestCycle.
093         * 
094         * @param cycle
095         *            the RequestCycle to use to locate the component
096         * @return IComponent a component that has been initialized for the given RequestCycle
097         */
098        public IComponent findComponent(IRequestCycle cycle)
099        {
100            IPage objPage = cycle.getPage(_pageName);
101            return objPage.getNestedComponent(_idPath);
102        }
103    
104        /**
105         * Returns the idPath of the component.
106         * 
107         * @return String the ID path of the component, or null if the address references a page, not a
108         *         component within a page.
109         */
110        public String getIdPath()
111        {
112            return _idPath;
113        }
114    
115        /**
116         * Returns the Page Name of the component.
117         * 
118         * @return String the Page Name of the component
119         */
120        public String getPageName()
121        {
122            return _pageName;
123        }
124    
125        /**
126         * @see java.lang.Object#hashCode()
127         */
128        public int hashCode()
129        {
130            int hash = _pageName.hashCode() * 31;
131            if (_idPath != null)
132                hash += _idPath.hashCode();
133            return hash;
134        }
135    
136        /**
137         * @see java.lang.Object#equals(Object)
138         */
139        public boolean equals(Object obj)
140        {
141            if (!(obj instanceof ComponentAddress))
142                return false;
143    
144            if (obj == this)
145                return true;
146    
147            ComponentAddress objAddress = (ComponentAddress) obj;
148            if (!getPageName().equals(objAddress.getPageName()))
149                return false;
150    
151            String idPath1 = getIdPath();
152            String idPath2 = objAddress.getIdPath();
153            return (idPath1 == idPath2) || (idPath1 != null && idPath1.equals(idPath2));
154        }
155    
156    }