Package juzu.impl.request

Source Code of juzu.impl.request.Stage$LifeCycle

/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.impl.request;

import juzu.MimeType;
import juzu.PropertyType;
import juzu.Response;
import juzu.impl.common.Spliterator;
import juzu.impl.common.Tools;
import juzu.impl.inject.spi.InjectionContext;
import juzu.impl.value.ValueType;
import juzu.io.Streamable;
import juzu.request.ApplicationContext;
import juzu.request.ClientContext;
import juzu.request.HttpContext;
import juzu.request.Phase;
import juzu.request.RequestContext;
import juzu.request.RequestParameter;
import juzu.request.SecurityContext;
import juzu.request.UserContext;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* A stage in the request pipeline.
*
* @author Julien Viet
*/
public abstract class Stage {

  /** . */
  private int index = 0;

  /** . */
  final Request request;

  /** . */
  final List<RequestFilter<?>> filters;

  public Request getRequest() {
    return request;
  }

  public Stage(Request request) {

    // Build the filter list
    List<RequestFilter<?>> filters = new ArrayList<RequestFilter<?>>();
    for (RequestFilter<?> filter : request.controllerPlugin.getInjectionContext().resolveInstances(RequestFilter.class)) {
      if (getClass().isAssignableFrom(filter.getStageType())) {
        filters.add(filter);
      }
    }

    //
    this.request = request;
    this.filters = filters;
  }

  public Response invoke() {
    if (index >= 0 && index < filters.size()) {
      RequestFilter plugin = filters.get(index);
      try {
        index++;
        return (Response)plugin.handle(this);
      }
      finally {
        index--;
      }
    }
    else if (index == filters.size()) {
      return response();
    }
    else {
      throw new AssertionError();
    }
  }

  protected abstract Response response();

  /**
   * This stage attempt to unmarshall the http entity when there is one.
   */
  public static class Unmarshalling extends Stage {

    public Unmarshalling(Request request) {
      super(request);
    }

    @Override
    protected Response response() {

      //
      Map<String, RequestParameter> parameterArguments = request.getParameterArguments();
      parameterArguments.putAll(request.bridge.getRequestArguments());

      //
      Map<ContextualParameter,Object> contextualArguments = request.getContextualArguments();
      for (ControlParameter controlParameter : request.handler.getParameters()) {
        if (controlParameter instanceof ContextualParameter) {
          ContextualParameter contextualParameter = (ContextualParameter)controlParameter;
          if (!contextualArguments.containsKey(contextualParameter)) {
            contextualArguments.put(contextualParameter, null);
          }
        }
      }
      contextualArguments.putAll(request.bridge.getContextualArguments(contextualArguments.keySet()));

      //
      ClientContext clientContext = request.bridge.getClientContext();
      if (clientContext != null) {
        String contentType = clientContext.getContentType();
        if (contentType != null) {
          Spliterator i = new Spliterator(contentType, ';');

          //
          String mediaType;
          if (i.hasNext()) {
            mediaType = i.next().trim();

            //
            if (!mediaType.equals("application/x-www-form-urlencoded")) {
              for (EntityUnmarshaller reader : Tools.loadService(EntityUnmarshaller.class, request.controllerPlugin.getApplication().getClassLoader())) {
                try {
                  if (reader.accept(mediaType)) {
                    reader.unmarshall(mediaType, clientContext, contextualArguments.entrySet(), parameterArguments);
                    break;
                  }
                }
                catch (IOException e) {
                  throw new UnsupportedOperationException("handle me gracefully", e);
                }
              }
            }
          }
        }
      }

      //
      return new Handler(request).invoke();
    }
  }

  /**
   * This stage prepares the handler for invocation, it determines the handler arguments and obtain the controller
   * object from the injection context of the application.
   */
  public static class Handler extends Stage {

    public Handler(Request request) {
      super(request);
    }

    public Response response() {

      ControllerHandler<?> handler = request.getHandler();
      InjectionContext<?, ?> manager = request.controllerPlugin.getInjectionContext();
      //
      Class<?> controllerType = handler.getType();
      request.controllerLifeCycle = manager.get(controllerType);
      if (request.controllerLifeCycle != null) {

        // Create context
        RequestContext context = new RequestContext(request, handler);

        // Build arguments
        Object[] args = new Object[handler.getParameters().size()];
        for (int i = 0;i < args.length;i++) {
          ControlParameter parameter = handler.getParameters().get(i);
          Object value;
          if (parameter instanceof PhaseParameter) {
            PhaseParameter phaseParam = (PhaseParameter)parameter;
            RequestParameter requestParam = request.getParameterArguments().get(phaseParam.getMappedName());
            if (requestParam != null) {
              ValueType<?> valueType = request.controllerPlugin.resolveValueType(phaseParam.getValueType());
              if (valueType != null) {
                List values = new ArrayList(requestParam.size());
                for (String s : requestParam) {
                  Object converted;
                  try {
                    converted = valueType.parse(phaseParam.getAnnotations(), s);
                  }
                  catch (Exception e) {
                    return Response.error(e);
                  }
                  values.add(converted);
                }
                value = phaseParam.getValue(values);
              } else {
                value = null;
              }
            } else {
              value = null;
            }
            Class<?> type = phaseParam.getType();
            if (value == null && type.isPrimitive()) {
              if (type == int.class) {
                value = 0;
              } else if (type == long.class) {
                value = 0L;
              } else if (type == byte.class) {
                value = (byte)0;
              } else if (type == short.class) {
                value = (short)0;
              } else if (type == boolean.class) {
                value = false;
              } else if (type == float.class) {
                value = 0.0f;
              } else if (type == double.class) {
                value = 0.0d;
              } else if (type == char.class) {
                value = '\u0000';
              }
            }
          } else if (parameter instanceof BeanParameter) {
            BeanParameter beanParam = (BeanParameter)parameter;
            Class<?> type = beanParam.getType();
            try {
              value = beanParam.createMappedBean(request.controllerPlugin, handler.requiresPrefix, type, beanParam.getName(), request.getParameterArguments());
            }
            catch (Exception e) {
              value = null;
            }
          } else {
            ContextualParameter contextualParameter = (ContextualParameter)parameter;
            value = request.getContextualArguments().get(contextualParameter);
            if (value == null) {
              Class<?> contextualType = contextualParameter.getType();
              if (RequestContext.class.isAssignableFrom(contextualType)) {
                value = context;
              } else if (HttpContext.class.isAssignableFrom(contextualType)) {
                value = request.getHttpContext();
              } else if (SecurityContext.class.isAssignableFrom(contextualType)) {
                value = request.getSecurityContext();
              } else if (ApplicationContext.class.isAssignableFrom(contextualType)) {
                value = request.getApplicationContext();
              } else if (UserContext.class.isAssignableFrom(contextualType)) {
                value = request.getUserContext();
              } else if (ClientContext.class.isAssignableFrom(contextualType) && (request.bridge.getPhase() == Phase.RESOURCE || request.bridge.getPhase() == Phase.ACTION)) {
                value = request.getClientContext();
              }
            }
          }
          args[i] = value;
        }

        // Get controller
        Object controller;
        try {
          controller = request.controllerLifeCycle.get();
        }
        catch (InvocationTargetException e) {
          return Response.error(e.getCause());
        }

        //
        Stage.LifeCycle lifeCycle = new LifeCycle(request, context, controller, args);

        //
        return lifeCycle.invoke();
      } else {
        // Handle that...
        return null;
      }
    }
  }

  /**
   * This stage takes care of triggering the controller life cycle when the controller implements the
   * {@link juzu.request.RequestLifeCycle} interface.
   */
  public static class LifeCycle extends Stage {

    /** . */
    private final RequestContext context;

    /** . */
    private final Object controller;

    /** . */
    private final Object[] args;

    public LifeCycle(Request request, RequestContext context, Object controller, Object[] args) {
      super(request);
      this.context = context;
      this.controller = controller;
      this.args = args;
    }

    @Override
    protected Response response() {

      // Begin request callback
      if (controller instanceof juzu.request.RequestLifeCycle) {
        try {
          ((juzu.request.RequestLifeCycle)controller).beginRequest(context);
        }
        catch (Exception e) {
          return new Response.Error(e);
        }
      }

      //
      Response response = context.getResponse();
      if (response == null) {
        Stage.Invoke invokeStage = new Invoke(request, context, controller, args);
        response = invokeStage.invoke();
        context.setResponse(response);

        // End request callback
        if (controller instanceof juzu.request.RequestLifeCycle) {
          try {
            ((juzu.request.RequestLifeCycle)controller).endRequest(context);
          }
          catch (Exception e) {
            context.setResponse(Response.error(e));
          }
        }

        //
        response = context.getResponse();
      }

      //
      return response;
    }
  }

  /**
   * This stage invokes the handler on the controller with the specified arguments.
   */
  public static class Invoke extends Stage {

    /** . */
    private final RequestContext context;

    /** . */
    private final Object controller;

    /** . */
    private final Object[] args;

    public Invoke(Request request, RequestContext context, Object controller, Object[] args) {
      super(request);

      //
      this.controller = controller;
      this.context = context;
      this.args = args;
    }

    public Object getController() {
      return controller;
    }

    public Object[] getArguments() {
      return args;
    }

    public Method getMethod() {
      return context.getHandler().getMethod();
    }

    @Override
    protected Response response() {
      try {
        Object ret = context.getHandler().getMethod().invoke(controller, args);

        //
        MimeType mimeType = null;
        for (Annotation annotation : context.getHandler().getMethod().getDeclaredAnnotations()) {
          if (annotation instanceof MimeType) {
            mimeType = (MimeType)annotation;
          } else {
            mimeType = annotation.annotationType().getAnnotation(MimeType.class);
          }
          if (mimeType != null && mimeType.value().length > 0) {
            // For now we stop but we should look at the accept types of the client
            // for doing some basic content negociation
            break;
          }
        }

        //
        if (ret instanceof Response) {
          // We should check that it matches....
          // btw we should try to enforce matching during compilation phase
          // @Action -> Response.Action
          // @View -> Response.Mime
          // as we can do it
          Response resp = (Response)ret;
          if (mimeType != null) {
            resp = resp.with(PropertyType.MIME_TYPE, mimeType.value()[0]);
          }
          return resp;
        } else if (ret != null && mimeType != null) {
          for (EntityMarshaller writer : Tools.loadService(EntityMarshaller.class, request.controllerPlugin.getApplication().getClassLoader())) {
            for (String s : mimeType.value()) {
              Streamable streamable = writer.marshall(s, context.getHandler().getMethod(), ret);
              if (streamable != null) {
                return Response.ok().with(PropertyType.MIME_TYPE, s).body(streamable);
              }
            }
          }
        }
        return null;
      }
      catch (InvocationTargetException e) {
        return Response.error(e.getCause());
      }
      catch (IllegalAccessException e) {
        throw new UnsupportedOperationException("hanle me gracefully", e);
      }
    }
  }
}
TOP

Related Classes of juzu.impl.request.Stage$LifeCycle

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.