001    /**
002     * Copyright 2005-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.uif.service.impl;
017    
018    import java.util.HashMap;
019    import java.util.List;
020    import java.util.Map;
021    
022    import org.apache.log4j.Logger;
023    import org.apache.log4j.Priority;
024    import org.kuali.rice.krad.service.DataDictionaryService;
025    import org.kuali.rice.krad.uif.UifConstants;
026    import org.kuali.rice.krad.uif.UifConstants.ViewStatus;
027    import org.kuali.rice.krad.uif.view.View;
028    import org.kuali.rice.krad.uif.service.ViewHelperService;
029    import org.kuali.rice.krad.uif.service.ViewService;
030    import org.kuali.rice.krad.uif.service.ViewTypeService;
031    import org.kuali.rice.krad.uif.UifConstants.ViewType;
032    import org.kuali.rice.krad.web.form.UifFormBase;
033    
034    /**
035     * Implementation of <code>ViewService</code>
036     *
037     * <p>
038     * Provides methods for retrieving View instances and carrying out the View
039     * lifecycle methods. Interacts with the configured <code>ViewHelperService</code>
040     * during the view lifecycle
041     * </p>
042     *
043     * @author Kuali Rice Team (rice.collab@kuali.org)
044     */
045    public class ViewServiceImpl implements ViewService {
046        private static final Logger LOG = Logger.getLogger(ViewServiceImpl.class);
047    
048        private DataDictionaryService dataDictionaryService;
049    
050        // TODO: remove once we can get beans by type from spring
051        private List<ViewTypeService> viewTypeServices;
052    
053        /**
054         * @see org.kuali.rice.krad.uif.service.ViewService#getViewById(java.lang.String)
055         */
056        public View getViewById(String viewId) {
057            if (LOG.isDebugEnabled()) {
058                LOG.debug("retrieving view instance for id: " + viewId);
059            }
060    
061            View view = dataDictionaryService.getViewById(viewId);
062            if (view == null) {
063                LOG.warn("View not found for id: " + viewId);
064            } else {
065                if (LOG.isDebugEnabled()) {
066                    LOG.debug("Updating view status to CREATED for view: " + view.getId());
067                }
068                view.setViewStatus(ViewStatus.CREATED);
069            }
070    
071            return view;
072        }
073    
074        /**
075         * Retrieves the <code>ViewTypeService</code> for the given view type, then builds up the index based
076         * on the supported view type parameters and queries the dictionary service to retrieve the view
077         * based on its type and index
078         *
079         * @see org.kuali.rice.krad.uif.service.ViewService#getViewByType(org.kuali.rice.krad.uif.UifConstants.ViewType,
080         *      java.util.Map<java.lang.String,java.lang.String>)
081         */
082        public View getViewByType(ViewType viewType, Map<String, String> parameters) {
083            ViewTypeService typeService = getViewTypeService(viewType);
084            if (typeService == null) {
085                throw new RuntimeException("Unable to find view type service for view type name: " + viewType);
086            }
087    
088            Map<String, String> typeParameters = typeService.getParametersFromRequest(parameters);
089    
090            Map<String, String> indexKey = new HashMap<String, String>();
091            for (Map.Entry<String, String> parameter : typeParameters.entrySet()) {
092                indexKey.put(parameter.getKey(), parameter.getValue());
093            }
094    
095            View view = dataDictionaryService.getViewByTypeIndex(viewType, indexKey);
096            if (view == null) {
097                LOG.warn("View not found for type: " + viewType);
098            } else {
099                LOG.debug("Updating view status to CREATED for view: " + view.getId());
100                view.setViewStatus(ViewStatus.CREATED);
101            }
102    
103            return view;
104        }
105    
106        /**
107         * @see org.kuali.rice.krad.uif.service.ViewService#buildView(org.kuali.rice.krad.uif.view.View, java.lang.Object,
108         * java.util.Map<java.lang.String,java.lang.String>)
109         */
110        public void buildView(View view, Object model, Map<String, String> parameters) {
111            // get the configured helper service for the view
112            ViewHelperService helperService = view.getViewHelperService();
113    
114            // populate view from request parameters
115            helperService.populateViewFromRequestParameters(view, parameters);
116    
117            // backup view request parameters on form for recreating lost views (session timeout)
118            ((UifFormBase) model).setViewRequestParameters(view.getViewRequestParameters());
119    
120            // run view lifecycle
121            performViewLifecycle(view, model, parameters);
122        }
123    
124        /**
125         * Initializes a newly created <code>View</code> instance. Each component of the tree is invoked
126         * to perform setup based on its configuration. In addition helper service methods are invoked to
127         * perform custom initialization
128         *
129         * @param view - view instance to initialize
130         * @param model - object instance containing the view data
131         * @param parameters - Map of key values pairs that provide configuration for the <code>View</code>, this
132         * is generally comes from the request and can be the request parameter Map itself. Any parameters
133         * not valid for the View will be filtered out
134         */
135        protected void performViewLifecycle(View view, Object model, Map<String, String> parameters) {
136            // get the configured helper service for the view
137            ViewHelperService helperService = view.getViewHelperService();
138    
139            // invoke initialize phase on the views helper service
140            // Heavily called method showed up on profile as a hotspot.  Putting log statements in checks cuts execution time by ~75%
141            if (LOG.isEnabledFor(Priority.INFO)) {
142                LOG.info("performing initialize phase for view: " + view.getId());
143            }
144            helperService.performInitialization(view, model);
145    
146            // do indexing
147            if (LOG.isDebugEnabled()) {
148                LOG.debug("processing indexing for view: " + view.getId());
149            }
150            view.index();
151    
152            // update status on view
153            if (LOG.isDebugEnabled()) {
154                LOG.debug("Updating view status to INITIALIZED for view: " + view.getId());
155            }
156            view.setViewStatus(ViewStatus.INITIALIZED);
157    
158            // Apply Model Phase
159            if (LOG.isEnabledFor(Priority.INFO)) {
160                LOG.info("performing apply model phase for view: " + view.getId());
161            }
162            helperService.performApplyModel(view, model);
163    
164            // do indexing
165            if (LOG.isEnabledFor(Priority.INFO)) {
166                LOG.info("reindexing after apply model for view: " + view.getId());
167            }
168            view.index();
169    
170            // Finalize Phase
171            if (LOG.isEnabledFor(Priority.INFO)) {
172                LOG.info("performing finalize phase for view: " + view.getId());
173            }
174            helperService.performFinalize(view, model);
175    
176            // do indexing
177            if (LOG.isEnabledFor(Priority.INFO)) {
178                LOG.info("processing final indexing for view: " + view.getId());
179            }
180            view.index();
181    
182            // update status on view
183            if (LOG.isDebugEnabled()) {
184                LOG.debug("Updating view status to FINAL for view: " + view.getId());
185            }
186            view.setViewStatus(ViewStatus.FINAL);
187        }
188    
189        public ViewTypeService getViewTypeService(UifConstants.ViewType viewType) {
190            if (viewTypeServices != null) {
191                for (ViewTypeService typeService : viewTypeServices) {
192                    if (viewType.equals(typeService.getViewTypeName())) {
193                        return typeService;
194                    }
195                }
196            }
197    
198            return null;
199        }
200    
201        public List<ViewTypeService> getViewTypeServices() {
202            return this.viewTypeServices;
203        }
204    
205        public void setViewTypeServices(List<ViewTypeService> viewTypeServices) {
206            this.viewTypeServices = viewTypeServices;
207        }
208    
209        protected DataDictionaryService getDataDictionaryService() {
210            return this.dataDictionaryService;
211        }
212    
213        public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
214            this.dataDictionaryService = dataDictionaryService;
215        }
216    
217    }