fried cake server---私の油揚げ餅(2)資源実行アーキテクチャ


リソース実行アーキテクチャ......少し玄ですが、正直に言うと、いわゆるリソース実行アーキテクチャは最初はif......else文の群れにすぎませんでしたが、開発が進むにつれて大きくなり、最後まで最悪でした.前回のSocketProcessクラスを覚えていますか?最初は実行方法が含まれていましたが、面倒でうるさいし、拡張しにくいです.

package server;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import jsp.JspConvertor;
import project.ProjectInfo;
import servlet.bean.ServletInfo;
import util.Constant;
import util.HttpError;
import util.LocalClassLoader;
import util.ServerMessage;
import webHttp.HttpRequestImpl;
import webHttp.HttpResponseImpl;
import webHttp.RequestHanler;
import webHttp.SessionPool;
/**
 *       
 *   :      ,     ,     
 *                       
 *        jms      
 *         
 * @author    
 *
 */
public class SocketProcess extends Thread {
	ServerSocketChannel serverSocket = null;

	/**
	 *        
	 * @param serverSocket         
	 */
	public SocketProcess(ServerSocketChannel serverSocket) {
		this.serverSocket = serverSocket;
	}

	/**
	 *  serverSocket     
	 *            servlet
	 *              
	 */
	public void run() {
		ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
		SocketChannel channel = null;
		try {
			//          
			channel = serverSocket.accept();
			if (channel != null && channel.read(buffer) > 0) {
				String requestInfo = new String(buffer.array(), 0, buffer
						.position());
				HttpRequestImpl request = RequestHanler
						.getHttpRequest(requestInfo);

				AppRunTime runtime = AppRunTime.getInstance();

				String[] uri = request.getContextPath().split(Constant.WEB_SP);

				ProjectInfo project = runtime.getProjectMap().get(uri[1]);
				if(project==null)return;
				//  session
				SessionPool sessionPool = SessionPool.getInstance(project.getId());
				HttpSession session = sessionPool.getSession(channel.socket().getInetAddress().getHostAddress());
				request.bind(session);

				//      servlet
			   if(excuteServlet(channel, project, request)==false) 
			   {
				   //     jsp
				   if(request.getServletPath().endsWith(Constant.FileType_SP_JSP))
					   excuteJsp(channel, project, request);
				   //              
				   else
					   excuteResource(channel, project, request);
				}
				//        
			    buffer.clear();
				if (channel.isOpen()) {
					buffer.put(" ".getBytes());
					buffer.flip();
					channel.write(buffer);
					channel.finishConnect();
					channel.close();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
    /**
     *        jsp  
     * @param channel         
	 * @param project       
	 * @param request     
     */
	private void excuteJsp(SocketChannel channel, ProjectInfo project,
			HttpServletRequest request) {
		String fileName = RequestHanler.loadRealPath(request);
		File jspFile = new File(fileName);
		//  jsp     
		if(!jspFile.exists())
		{
			sendExceptionMessage(channel,HttpError.ERROR_404);
			return;
		}
		JspConvertor convertor  = new JspConvertor(jspFile,project);
		try {
			File servletFile = convertor.getCompiledServlet();
			 ClassLoader loader = LocalClassLoader.getInstance(servletFile.getParent());
			 HttpServlet servlet = (HttpServlet) loader.loadClass(servletFile.getName().replace(Constant.FileType_SP_Class, "")).newInstance();
			 HttpServletResponse response = new HttpResponseImpl(channel);
			 servlet.service(request, response);
		} catch (Exception e) {
			sendExceptionMessage(channel,HttpError.ERROR_404);
		}
	}
	/**
	 *            ,  error404 page not found   
	 * @param channel
	 * @param message
	 */
	private void sendExceptionMessage(SocketChannel channel ,String message){
		ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
		buffer.put(HttpError.ERROR_404.getBytes());
		buffer.flip();
		try {
			channel.write(buffer);
		} catch (IOException e) {
			System.err.println(ServerMessage.connection_exception);
		}
		buffer.clear();
	}
	/**
	 *       
	 * 
	 * @param channel         
	 * @param project       
	 * @param request     
	 * @throws Exception     
	 */
	private void excuteResource(SocketChannel channel, ProjectInfo project, HttpServletRequest request) throws Exception {
		ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
		String fileName = RequestHanler.loadRealPath(request);
		buffer.clear();
		File file = new File(fileName);
		if (file.exists() && file.canRead()) {
			FileChannel fc = new FileInputStream(file).getChannel();
			while (fc.read(buffer) > 0) {
				buffer.flip();
				channel.write(buffer);
				buffer.clear();
			}
		} else {//          ,     404 page not found    
			sendExceptionMessage(channel,HttpError.ERROR_404);
		}
	}

	/**
	 *   servlet  
	 * 
	 * @param channel               
	 * @param project             
	 * @param request           
	 * @return                    servlet   
	 * @throws Exception if     
	 */
	private boolean excuteServlet(SocketChannel channel, ProjectInfo project,HttpServletRequest request) throws Exception {
		
		for (ServletInfo info : project.getServletInfo()) {
			 //    
			 Pattern p = Pattern.compile(Constant.WEB_SP+project.getWebPath()+info.getUrl_pattern());
			 Matcher m = p.matcher(request.getRequestURI());
			 if (m.matches()==false) continue;
			 //    
			 ClassLoader loader = LocalClassLoader.getInstance(project .getPatch());
			 HttpServlet servlet = (HttpServlet) loader.loadClass( info.getServletClass()).newInstance();
			 HttpServletResponse response = new HttpResponseImpl(channel);
			 //   filter    servlet  
			 FilterChain chain = info.getFilterChain();
			 chain.doFilter(request, response);
			 servlet.init(info.getServletConfig());
			 servlet.service(request, response);
			 servlet.destroy();
			 return true;
		}
		return false;
	}
}

これが第1版のリソースアクチュエータで、とても乱れているでしょう
その後、リソース実行アーキテクチャを再構築し、エージェントモデルを作りました.
このラックは2つのインタフェース、1つのエージェントクラス、およびいくつかの実装クラスから構成されています.
1つ目はエフェクタインタフェースであり、このインタフェースを実現したクラスはhttpリクエストを受け入れて応答することができる.

public interface Executor {
	/**
	 *     ,           
	 *         ,          
	 *         
	 * @param request      
	 * @param response     
	 */
	public void forward(HttpServletRequest request,HttpServletResponse response) throws Exception;
	
}
第2のインタフェースはExecutorのサブインタフェースCheckableExecutorが実現したクラスが実行可能かどうかを判断する

public interface CheckableExecutor extends Executor{

	public void init(ProjectInfo project);
	/**
	 *            
	 * @return
	 */
	public boolean isExecutable(HttpServletRequest request);
}

さらにエージェントクラスを実行するには、このクラスは責任チェーンモードを使用していますが、実はこのexecutorArrayはプロファイルに配置できますが、まだそんなに遠いことは考えていないので、先に置いておきました.しかし、拡張は依然として容易であり、CheckableExecutorインタフェースを実現し、クラス名をexecutorArray配列に記入して登録すれば、実行シーケンスに追加できます.

package executor;

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

import project.ProjectInfo;
import executor.impl.JspExecutor;
import executor.impl.ResourceExecutor;
import executor.impl.ServletExecutor;

public class BaseExecutor implements Executor {
	
	@SuppressWarnings("unchecked")
	private Class<CheckableExecutor>[] executorArray = new Class[]{JspExecutor.class,ServletExecutor.class,ResourceExecutor.class}; 
	//  executor
	private ProjectInfo project;
	/**
	 *     
	 * @param project
	 */
	public BaseExecutor(ProjectInfo project){
		this.project = project;
	}
	/**
	 *           
	 *            
	 * @param request
	 * @return
	 * @throws Exception 
	 * @throws InstantiationException 
	 */
	public Executor getExecutor(HttpServletRequest request) throws InstantiationException, Exception {
		//     
		for(Class<CheckableExecutor> exeClass:executorArray)
		{
			CheckableExecutor  executor = exeClass.newInstance();
			executor.init(project);
			if(executor.isExecutable(request)) return executor;
		}
		return null;
	}

	
	/**
	 *          ,       
	 */
	@Override
	public void forward(HttpServletRequest request,HttpServletResponse response) throws Exception{
		Executor exe = getExecutor(request);
		exe.forward(request, response);
	}

}

次はJspExecutor、サーブレットExecutor、ResourceExecutorの3つの実装クラスです.
jspリソース、servletリソース、通常のファイルリソースにそれぞれ対応していますが、前の2つのエフェクタは環境外のクラスロード、jspコンパイル、システムデータ構造など多くの問題に関連しています.後の章に置きます.
次は一般的なエクスプローラです

package executor.impl;

import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

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

import project.ProjectInfo;

import util.HttpError;
import webHttp.RequestHanler;
import exceptions.HttpException;
import executor.CheckableExecutor;

public class ResourceExecutor implements CheckableExecutor {

	public void init(ProjectInfo project) {
		//     
	}
	/**
	 *       
	 */
	@Override
	public void forward(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
		String fileName = RequestHanler.loadRealPath(request);
		buffer.clear();
		File file = new File(fileName);
		if (file.exists() && file.canRead()) {
			FileChannel fc = new FileInputStream(file).getChannel();
			while (fc.read(buffer) > 0) {
				buffer.flip();
				response.getOutputStream().write(buffer.array());
				buffer.clear();
			}
		} else {//          ,     404 page not found    
			throw new HttpException(HttpError.ERROR_404);
		}
	}

	@Override
	/**
	 *              
	 * ResourceExecutor,           ,       ,          
	 */
	public boolean isExecutable(HttpServletRequest request) {
		return true;
	}

}

「String file Name=RequestHanler.loadRealPath(request);」を除いてreviewしました.この一言のほかに、ほかに疑問はないはずです.この文については、request urlからファイルリソースへのマッピングですが、最初は簡単なフォルダパスマッピングをすればよかったのですが、その後、プロジェクトマウントProjectDeployerといくつかの関連をしましたが、この実現は重要ではありません.皆さんは理解しているはずです.
では、これらの種類があれば、私たちの揚げ餅は簡単な応答ができるはずですが...
興味のある友達は自分で書いてみてもいいですが、実はこの一歩は、難しくはありません.難しいのは後ろです.
へへへ、次号は遠端classLoaderの書き方とserverのデータ構造を紹介して、ゆっくりと