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.wicket.core.request.handler;
018
019import org.apache.wicket.Page;
020import org.apache.wicket.feedback.FeedbackDelay;
021import org.apache.wicket.request.component.IRequestableComponent;
022import org.apache.wicket.request.component.IRequestablePage;
023import org.apache.wicket.request.mapper.parameter.PageParameters;
024import org.apache.wicket.util.lang.Args;
025
026/**
027 * Extension of {@link PageProvider} that is also capable of providing a Component belonging to the
028 * page.
029 *
030 * @see PageProvider
031 *
032 * @author Matej Knopp
033 */
034public class PageAndComponentProvider extends PageProvider implements IPageAndComponentProvider
035{
036        private IRequestableComponent component;
037
038        private String componentPath;
039
040        /**
041         * @see PageProvider#PageProvider(IRequestablePage)
042         *
043         * @param page
044         * @param componentPath
045         */
046        public PageAndComponentProvider(IRequestablePage page, String componentPath)
047        {
048                super(page);
049                setComponentPath(componentPath);
050        }
051
052        /**
053         * @see PageProvider#PageProvider(IRequestablePage)
054         *
055         * @param page
056         * @param component
057         */
058        public PageAndComponentProvider(IRequestablePage page, IRequestableComponent component)
059        {
060                super(page);
061
062                Args.notNull(component, "component");
063
064                this.component = component;
065        }
066
067        /**
068         * @see PageProvider#PageProvider(Class, PageParameters)
069         *
070         * @param pageClass
071         * @param pageParameters
072         * @param componentPath
073         */
074        public PageAndComponentProvider(Class<? extends IRequestablePage> pageClass,
075                PageParameters pageParameters, String componentPath)
076        {
077                super(pageClass, pageParameters);
078                setComponentPath(componentPath);
079        }
080
081        /**
082         * @see PageProvider#PageProvider(Class)
083         *
084         * @param pageClass
085         * @param componentPath
086         */
087        public PageAndComponentProvider(Class<? extends IRequestablePage> pageClass,
088                String componentPath)
089        {
090                super(pageClass);
091                setComponentPath(componentPath);
092        }
093
094        /**
095         * @see PageProvider#PageProvider(Integer, Class, Integer)
096         *
097         * @param pageId
098         * @param pageClass
099         * @param renderCount
100         * @param componentPath
101         */
102        public PageAndComponentProvider(int pageId, Class<? extends IRequestablePage> pageClass,
103                Integer renderCount, String componentPath)
104        {
105                super(pageId, pageClass, renderCount);
106                setComponentPath(componentPath);
107        }
108
109        /**
110         * @see PageProvider#PageProvider(Integer, Class, Integer)
111         *
112         * @param pageId
113         * @param pageClass
114         * @param pageParameters
115         * @param renderCount
116         * @param componentPath
117         */
118        public PageAndComponentProvider(Integer pageId, Class<? extends IRequestablePage> pageClass,
119                PageParameters pageParameters, Integer renderCount, String componentPath)
120        {
121                super(pageId, pageClass, pageParameters, renderCount);
122                setComponentPath(componentPath);
123        }
124
125        /**
126         * @see PageProvider#PageProvider(Integer, Integer)
127         *
128         * @param pageId
129         * @param renderCount
130         * @param componentPath
131         */
132        public PageAndComponentProvider(int pageId, Integer renderCount, String componentPath)
133        {
134                super(pageId, renderCount);
135                setComponentPath(componentPath);
136        }
137
138        public PageAndComponentProvider(IRequestablePage page, IRequestableComponent component,
139                PageParameters parameters)
140        {
141                super(page);
142
143                Args.notNull(component, "component");
144
145                this.component = component;
146                if (parameters != null)
147                {
148                        setPageParameters(parameters);
149                }
150        }
151
152        @Override
153        public IRequestableComponent getComponent()
154        {
155                if (component == null)
156                {
157                        IRequestablePage page = getPageInstance();
158                        component = page != null ? page.get(componentPath) : null;
159                        if (component == null)
160                        {
161
162                                /*
163                                 * on stateless pages it is possible that the component may not yet exist because it
164                                 * couldve been created in one of the lifecycle callbacks of this page. Lets invoke
165                                 * the callbacks to give the page a chance to create the missing component.
166                                 */
167
168                                // make sure this page instance was just created so the page can be stateless
169                                if (page.isPageStateless())
170                                {
171                                        Page p = (Page)page;
172                                        p.internalInitialize();
173                                        
174                                        // preparation of feedbacks is delayed into the render phase
175                                        try (FeedbackDelay delay = new FeedbackDelay(p.getRequestCycle())) {
176                                                p.beforeRender();
177                                                p.markRendering(false);
178                                                
179                                                // note: no invocation of delay.onBeforeRender() 
180                                        }
181                                        component = page.get(componentPath);
182                                }
183                        }
184                }
185                if (component == null)
186                {
187                        throw new ComponentNotFoundException("Could not find component '" + componentPath +
188                                "' on page '" + getPageClass());
189                }
190                return component;
191        }
192
193        /**
194         * @see org.apache.wicket.core.request.handler.IPageAndComponentProvider#getComponentPath()
195         */
196        @Override
197        public String getComponentPath()
198        {
199                if (componentPath != null)
200                {
201                        return componentPath;
202                }
203                else
204                {
205                        return component.getPageRelativePath();
206                }
207        }
208
209        /**
210         *
211         * @param componentPath
212         */
213        private void setComponentPath(String componentPath)
214        {
215                Args.notNull(componentPath, "componentPath");
216
217                this.componentPath = componentPath;
218        }
219}