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
015package org.apache.tapestry.util;
016
017import java.io.Serializable;
018
019import org.apache.hivemind.util.Defense;
020import org.apache.tapestry.IComponent;
021import org.apache.tapestry.INamespace;
022import org.apache.tapestry.IPage;
023import 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 */
039public 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}