com.laxser.blitz.web.instruction.InstructionExecutorImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.laxser.blitz.web.instruction.InstructionExecutorImpl.java

Source

/*
 * Copyright 2007-2009 the original author or authors.
 *
 * 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.laxser.blitz.web.instruction;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;

import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import com.laxser.blitz.util.SpringUtils;
import com.laxser.blitz.web.Invocation;
import com.laxser.blitz.web.impl.thread.InvocationBean;

/**
 * @author  [qieqie.wang@gmail.com]
 */
public class InstructionExecutorImpl implements InstructionExecutor {

    private Log logger = LogFactory.getLog(getClass());

    @Override
    public Object render(Invocation inv, Object instruction) throws IOException, ServletException, Exception {
        instruction = translatesToInstructionObject((InvocationBean) inv, instruction);
        if (instruction != null && !Thread.currentThread().isInterrupted()) {
            ((Instruction) instruction).render(inv);
        }
        return instruction;
    }

    /**
     * @param inv
     * @param instruction
     * @return
     * @throws StackOverflowError
     */
    private Instruction translatesToInstructionObject(InvocationBean inv, Object instruction)
            throws StackOverflowError {
        int count = 0;
        while (!(instruction instanceof Instruction)) {
            if (count++ > 50) {
                throw new StackOverflowError("Unable to parse the instruction to an"
                        + " Instruction object less than " + count + " times. Is the instruction"
                        + " that returned by your controller" + " action is right?");
            }

            if (Thread.interrupted() || instruction == null) {
                return null;
            } else {
                if (instruction.getClass() != String.class
                        && !ClassUtils.isPrimitiveOrWrapper(instruction.getClass())
                        && instruction.getClass().getComponentType() == null
                        && instruction.getClass().getAnnotation(Component.class) != null) {
                    SpringUtils.autowire(instruction, inv.getApplicationContext());
                }
                instruction = parseInstruction(inv, instruction);
            }
        }
        return (Instruction) instruction;
    }

    protected Object parseInstruction(Invocation inv, Object ins) {
        if (logger.isDebugEnabled()) {
            logger.debug("parset instruction:" + ins.getClass().getName() + ": '" + ins + "'");
        }
        if (ClassUtils.isPrimitiveOrWrapper(ins.getClass())) {
            return Text.text(ins);
        } else if (ins instanceof CharSequence) {
            String str = ins.toString();
            if (str.length() == 0 || str.equals("@")) {
                return null;
            }
            if (str.charAt(0) == '@') {
                return Text.text(str.substring(1)); // content-type?@HttpFeatures
            }
            if (str.charAt(0) == '/') {
                return new ViewInstruction(str);
            }
            if (str.startsWith("r:") || str.startsWith("redirect:")) {
                StringInstruction si = new StringInstruction(false, str.substring(str.indexOf(':') + 1));
                if (si.innerInstruction.startsWith("http://") || si.innerInstruction.startsWith("https://")) {
                    return Redirect.location(si.innerInstruction);
                }
                return si;
            }
            if (str.startsWith("pr:") || str.startsWith("perm-redirect:")) {
                StringInstruction si = new StringInstruction(false, str.substring(str.indexOf(':') + 1));
                si.permanentlyWhenRedirect = true;
                if (si.innerInstruction.startsWith("http://") || si.innerInstruction.startsWith("https://")) {
                    return si.permanentlyIfNecessary(Redirect.location(si.innerInstruction));
                }
                return si;
            }
            if (str.startsWith("f:") || str.startsWith("forward:")) {
                return new StringInstruction(true, str.substring(str.indexOf(':') + 1));
            }
            if (str.startsWith("e:") || str.startsWith("error:")) {
                int begin = str.indexOf(':') + 1;
                int codeEnd = str.indexOf(';');
                if (codeEnd == -1) {
                    String text = str.substring(begin);
                    if (text.length() > 0 && NumberUtils.isNumber(text)) {
                        return HttpError.code(Integer.parseInt(text));
                    }
                    return HttpError.code(500, text);
                } else {
                    return HttpError.code(Integer.parseInt(str.substring(begin, codeEnd)),
                            str.substring(codeEnd + 1).trim());
                }
            }
            if (str.startsWith("s:") || str.startsWith("status:")) {
                int begin = str.indexOf(':') + 1;
                int codeEnd = str.indexOf(';', begin);
                if (codeEnd == -1) {
                    inv.getResponse().setStatus(Integer.parseInt(str.substring(begin)));
                    return null;
                } else {
                    // setStatus(int, String)???';'??msg
                    // sendError?
                    inv.getResponse().setStatus(Integer.parseInt(str.substring(begin, codeEnd)));
                    for (int i = codeEnd; i < str.length(); i++) {
                        if (str.charAt(i) != ' ') {
                            str = str.substring(i + 1);
                            break;
                        }
                    }
                }
            }
            if (str.equals(":continue")) {
                return null;
            }
            return new StringInstruction(null, str);
        } else if (ins.getClass() == StringInstruction.class) {
            StringInstruction fr = (StringInstruction) ins;
            String str = fr.innerInstruction;
            int queryIndex = str.indexOf('?');
            for (int i = (queryIndex == -1) ? str.length() - 1 : queryIndex - 1; i >= 0; i--) {
                if (str.charAt(i) != ':') {
                    continue;
                }
                if (i > 0 && str.charAt(i - 1) == '\\') { // ?
                    str = str.substring(0, i - 1) + str.substring(i);
                    i--;
                    continue;
                }
                int cmdEnd = i;
                int cmdBeforeBegin = i - 1;
                while (cmdBeforeBegin >= 0 && str.charAt(cmdBeforeBegin) != ':') {
                    cmdBeforeBegin--;
                }
                String prefix = str.subSequence(cmdBeforeBegin + 1, cmdEnd).toString();
                String body = str.subSequence(i + 1, str.length()).toString();
                if ("a".equals(prefix) || "action".equals(prefix)) {
                    if (fr.isReirect()) {
                        return fr.permanentlyIfNecessary(Redirect.action(body));
                    } else {
                        return Forward.action(body);
                    }
                }
                if ("c".equals(prefix) || "controller".equals(prefix)) {
                    if (fr.isReirect()) {
                        return fr.permanentlyIfNecessary(Redirect.controller(body));
                    } else {
                        return Forward.controller(body);
                    }
                }
                if ("m".equals(prefix) || "module".equals(prefix)) {
                    if (fr.isReirect()) {
                        return fr.permanentlyIfNecessary(Redirect.module(body));
                    } else {
                        return Forward.module(body);
                    }
                }
                logger.warn("skip the prefix '" + prefix + ":' of " + str);
                if (fr.isReirect()) {
                    return fr.permanentlyIfNecessary(Redirect.location(str));
                } else if (fr.isForward()) {
                    return Forward.path(str);
                } else {
                    return new ViewInstruction(str);
                }
            }
            if (fr.isReirect()) {
                return fr.permanentlyIfNecessary(Redirect.location(str));
            } else if (fr.isForward()) {
                return Forward.path(str);
            }
            return new ViewInstruction(str);
        } else if (ins instanceof InputStream) {
            return new InputStreamInstruction((InputStream) ins);
        } else if (ins instanceof byte[]) {
            return new InputStreamInstruction(new ByteArrayInputStream((byte[]) ins));
        } else {
            return Text.text(ins.toString());
        }
    }

    private class StringInstruction {

        Boolean forward;

        String innerInstruction;

        boolean permanentlyWhenRedirect = false;

        public StringInstruction(Boolean forward, String innerInstruction) {
            super();
            this.forward = forward;
            this.innerInstruction = innerInstruction;
        }

        public RedirectInstruction permanentlyIfNecessary(RedirectInstruction redirectInstruction) {
            if (permanentlyWhenRedirect) {
                redirectInstruction.permanently();
            }
            return redirectInstruction;
        }

        public boolean isReirect() {
            return forward != null && !forward.booleanValue();
        }

        public boolean isForward() {
            return forward != null && forward.booleanValue();
        }

        @Override
        public String toString() {
            return forward == null ? "" : (forward ? "f:" : "r:") + innerInstruction;
        }
    }

}