001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krad.uif.service.impl;
017
018import java.util.HashMap;
019import java.util.List;
020import java.util.Map;
021
022import org.apache.log4j.Logger;
023import org.apache.log4j.Priority;
024import org.kuali.rice.krad.service.DataDictionaryService;
025import org.kuali.rice.krad.uif.UifConstants;
026import org.kuali.rice.krad.uif.UifConstants.ViewStatus;
027import org.kuali.rice.krad.uif.view.View;
028import org.kuali.rice.krad.uif.service.ViewHelperService;
029import org.kuali.rice.krad.uif.service.ViewService;
030import org.kuali.rice.krad.uif.service.ViewTypeService;
031import org.kuali.rice.krad.uif.UifConstants.ViewType;
032import 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 */
045public 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}