com.wavemaker.runtime.server.ControllerBase.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.runtime.server.ControllerBase.java

Source

/*
 *  Copyright (C) 2012-2013 CloudJee, Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.wavemaker.runtime.server;

import java.io.File;
import java.io.IOException;
import java.sql.Blob;
import java.sql.Clob;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.NDC;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.AbstractController;

import com.wavemaker.common.MessageResource;
import com.wavemaker.common.WMException;
import com.wavemaker.common.WMRuntimeException;
import com.wavemaker.json.JSONArray;
import com.wavemaker.json.JSONState;
import com.wavemaker.json.type.FieldDefinition;
import com.wavemaker.json.type.GenericFieldDefinition;
import com.wavemaker.json.type.reflect.MapReflectTypeDefinition;
import com.wavemaker.json.type.reflect.ReflectTypeState;
import com.wavemaker.json.type.reflect.ReflectTypeUtils;
import com.wavemaker.json.type.reflect.converters.DateTypeDefinition;
import com.wavemaker.json.type.reflect.converters.FileTypeDefinition;
import com.wavemaker.runtime.RuntimeAccess;
import com.wavemaker.runtime.server.json.converters.BlobTypeDefinition;
import com.wavemaker.runtime.server.json.converters.ClobTypeDefinition;
import com.wavemaker.runtime.server.view.TypedView;
import com.wavemaker.runtime.service.ParsedServiceArguments;
import com.wavemaker.runtime.service.ServiceManager;
import com.wavemaker.runtime.service.ServiceWire;
import com.wavemaker.runtime.service.TypedServiceReturn;
import com.wavemaker.runtime.service.events.ServiceEventNotifier;
import com.wavemaker.runtime.service.events.ServletEventNotifier;
import com.wavemaker.runtime.service.response.RootServiceResponse;

/**
 * @author Matt Small
 */
public abstract class ControllerBase extends AbstractController {

    /** Logger that is available to subclasses */
    protected final Log logger = LogFactory.getLog(getClass());

    protected ServiceResponse serviceResponse;

    private ServiceManager serviceManager;

    private ServiceEventNotifier serviceEventNotifier;

    private ServletEventNotifier servletEventNotifier;

    @SuppressWarnings("deprecation")
    private com.activegrid.runtime.AGRuntime runtime;

    private InternalRuntime internalRuntime;

    private RuntimeAccess runtimeAccess;

    /**
     * Create the default JSONState.
     * 
     * @return
     */
    public static JSONState createJSONState() {

        JSONState jsonState = new JSONState();

        jsonState.setCycleHandler(JSONState.CycleHandler.NO_PROPERTY);

        // value conversions
        jsonState.getTypeState().addType(new DateTypeDefinition(java.util.Date.class));
        jsonState.getTypeState().addType(new DateTypeDefinition(java.sql.Date.class));
        jsonState.getTypeState().addType(new DateTypeDefinition(java.sql.Timestamp.class));
        jsonState.getTypeState().addType(new DateTypeDefinition(java.sql.Time.class));

        jsonState.getTypeState().addType(new FileTypeDefinition(File.class));
        jsonState.getTypeState().addType(new BlobTypeDefinition(Blob.class));
        jsonState.getTypeState().addType(new ClobTypeDefinition(Clob.class));

        return jsonState;
    }

    @Override
    public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {

        if (request == null) {
            throw new WMRuntimeException(MessageResource.SERVER_NOREQUEST);
        } else if (response == null) {
            throw new WMRuntimeException(MessageResource.SERVER_NORESPONSE);
        }

        ModelAndView ret;
        try {
            this.runtimeAccess.setStartTime(System.currentTimeMillis());
            // add logging
            StringBuilder logEntry = new StringBuilder();
            HttpSession session = request.getSession(false);
            if (session != null) {
                logEntry.append("session " + session.getId() + ", ");
            }
            logEntry.append("thread " + Thread.currentThread().getId());
            NDC.push(logEntry.toString());

            // default responses to the DEFAULT_ENCODING
            response.setCharacterEncoding(ServerConstants.DEFAULT_ENCODING);

            getServletEventNotifier().executeStartRequest();
            initializeRuntime(request, response);

            // execute the request
            ret = executeRequest(request, response);

            getServletEventNotifier().executeEndRequest();
        } catch (Throwable t) {
            this.logger.error(t.getMessage(), t);
            String message = t.getMessage();
            if (!StringUtils.hasLength(message)) {
                message = t.toString();
            }
            if (this.serviceResponse != null && !this.serviceResponse.isPollingRequest()
                    && this.serviceResponse.getConnectionTimeout() > 0
                    && System.currentTimeMillis()
                            - this.runtimeAccess.getStartTime() > (this.serviceResponse.getConnectionTimeout() - 3)
                                    * 1000) {
                this.serviceResponse.addError(t);
            }
            return handleError(message, t);
        } finally {
            RuntimeAccess.setRuntimeBean(null);
            NDC.pop();
            NDC.remove();
        }

        return ret;
    }

    /**
     * Perform runtime initialization, after the base runtime has been initialized.
     * 
     * @param request The current request.
     */
    protected void initializeRuntimeController(HttpServletRequest request) {
        JSONState jsonConfig = ControllerBase.createJSONState();
        getInternalRuntime().setJSONState(jsonConfig);
    }

    /**
     * Actually handle the request; control is passed to this from handleRequestInternal.
     * 
     * @param request The current request.
     * @param response The current response.
     * @return An appropriate ModelAndView.
     * @throws IOException
     * @throws WMException
     */
    protected abstract ModelAndView executeRequest(HttpServletRequest request, HttpServletResponse response)
            throws IOException, WMException;

    /**
     * Handle an error, either by returning a ModelAndView, or by throwing an WMRuntimeException.
     * 
     * @param message The error message.
     * @param t The throwable that cause the exception.
     * @return
     */
    protected abstract ModelAndView handleError(String message, Throwable t);

    /**
     * Get a view appropriate for this controller.
     * 
     * @return The view.
     */
    protected abstract View getView();

    /**
     * Return the ModelAndView object, with the key set appropriately for the type of resultObject.
     * 
     * Current behaviour:
     * <ul>
     * <li>If resultObject is an instance of {@link RootServiceResponse}, set resultObject in the Model with a key of
     * {@link ServerConstants#ROOT_MODEL_OBJECT_KEY}.</li>
     * <li>Otherwise, set resultObject into the Model with a key of {@link ServerConstants#RESULTS_PART}.</li>
     * </ul>
     * 
     * @param view The current view.
     * @param typedServiceReturn The result of the method invocation.
     * @return A new ModelAndView object, set up properly depending on the type of resultObject.
     */
    protected ModelAndView getModelAndView(TypedView view, TypedServiceReturn typedServiceReturn) {

        ModelAndView ret;

        FieldDefinition fd;
        if (typedServiceReturn.getReturnType() != null) {
            fd = typedServiceReturn.getReturnType();
        } else {
            fd = new GenericFieldDefinition();
        }

        Object resultObject = typedServiceReturn.getReturnValue();
        if (resultObject != null && resultObject instanceof RootServiceResponse) {
            view.setRootType(fd);
            ret = new ModelAndView(view, ServerConstants.ROOT_MODEL_OBJECT_KEY, resultObject);
        } else {
            MapReflectTypeDefinition mrtd = new MapReflectTypeDefinition();
            mrtd.setKeyFieldDefinition(
                    ReflectTypeUtils.getFieldDefinition(String.class, new ReflectTypeState(), false, null));
            mrtd.setValueFieldDefinition(fd);

            view.setRootType(new GenericFieldDefinition(mrtd));

            ret = new ModelAndView(view, ServerConstants.RESULTS_PART, resultObject);
        }

        return ret;
    }

    protected TypedServiceReturn invokeMethod(ServiceWire sw, String method, JSONArray jsonArgs,
            Map<String, Object[]> mapParams) throws WMException {
        return invokeMethod(sw, method, jsonArgs, mapParams, null);
    }

    protected TypedServiceReturn invokeMethod(ServiceWire sw, String method, JSONArray jsonArgs,
            Map<String, Object[]> mapParams, ServiceResponse serviceResponse) throws WMException {

        if (jsonArgs != null && mapParams != null) {
            throw new WMRuntimeException(MessageResource.BOTH_ARGUMENT_TYPES, jsonArgs, mapParams);
        } else if (sw == null) {
            throw new NullArgumentException("sw");
        }

        sw.getServiceType().setup(sw, this.internalRuntime, this.runtimeAccess);

        JSONState jsonState = getInternalRuntime().getJSONState();

        ParsedServiceArguments args;
        if (mapParams != null) {
            args = sw.getServiceType().parseServiceArgs(sw, method, mapParams, jsonState);
        } else {
            args = sw.getServiceType().parseServiceArgs(sw, method, jsonArgs, jsonState);
        }

        getInternalRuntime().setDeserializedProperties(args.getGettersCalled());

        return ServerUtils.invokeMethodWithEvents(getServiceEventNotifier(), sw, method, args, jsonState, false,
                serviceResponse);
    }

    @SuppressWarnings("deprecation")
    private void initializeRuntime(HttpServletRequest request, HttpServletResponse response) {

        RuntimeAccess.setRuntimeBean(getRuntimeAccess());
        InternalRuntime.setInternalRuntimeBean(getInternalRuntime());

        // when you remove this, also remove the SuppressWarnings anno
        com.activegrid.runtime.AGRuntime.setRuntimeBean(getRuntime());

        getRuntimeAccess().setRequest(request);
        getRuntimeAccess().setResponse(response);
        initializeRuntimeController(request);
    }

    public void setServiceManager(ServiceManager spm) {
        this.serviceManager = spm;
    }

    public ServiceManager getServiceManager() {
        return this.serviceManager;
    }

    public ServletEventNotifier getServletEventNotifier() {
        return this.servletEventNotifier;
    }

    public void setServletEventNotifier(ServletEventNotifier servletEventNotifier) {
        this.servletEventNotifier = servletEventNotifier;
    }

    public ServiceEventNotifier getServiceEventNotifier() {
        return this.serviceEventNotifier;
    }

    public void setServiceEventNotifier(ServiceEventNotifier serviceEventNotifier) {
        this.serviceEventNotifier = serviceEventNotifier;
    }

    @SuppressWarnings("deprecation")
    public com.activegrid.runtime.AGRuntime getRuntime() {
        return this.runtime;
    }

    @SuppressWarnings("deprecation")
    public void setRuntime(com.activegrid.runtime.AGRuntime runtime) {
        this.runtime = runtime;
    }

    public InternalRuntime getInternalRuntime() {
        return this.internalRuntime;
    }

    public void setInternalRuntime(InternalRuntime internalRuntime) {
        this.internalRuntime = internalRuntime;
    }

    public RuntimeAccess getRuntimeAccess() {
        return this.runtimeAccess;
    }

    public void setRuntimeAccess(RuntimeAccess runtimeAccess) {
        this.runtimeAccess = runtimeAccess;
    }

    public void setServiceResponse(ServiceResponse serviceResponse) {
        this.serviceResponse = serviceResponse;
    }
}