package websquare.http;                                                                                                                                                                 
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import websquare.WebSquareConfig;
import websquare.document.util.MimeUtil;
import websquare.exception.PostControllerException;
import websquare.http.controller.IDisposable;
import websquare.http.controller.IPostController;
import websquare.http.controller.JavascriptAllPluginResourceController;
import websquare.http.controller.JavascriptEngineResourceController;
import websquare.http.controller.JavascriptPluginResourceController;
import websquare.http.controller.JavascriptResourceController;
import websquare.http.controller.PreviewController;
import websquare.http.controller.ResourceController;
import websquare.http.controller.WebSquareController;
import websquare.http.controller.grid.read.CSVToGrid;
import websquare.http.controller.grid.read.ExcelToGrid;
import websquare.http.controller.grid.write.GridToCSV;
import websquare.http.controller.grid.write.GridToExcel;
import websquare.http.controller.upload.DefaultFileDeleteController;
import websquare.http.controller.upload.DefaultFileUploadController;
import websquare.http.controller.upload.DefaultImageFileUploadController;
import websquare.http.util.IPathMatcher;
import websquare.http.util.SimplePathMatcher;
import websquare.i18n.I18N;
import websquare.logging.util.LogUtil;
import websquare.upload.MultiPartResolver;
import websquare.util.LoadImg;
import websquare.util.ServerTimeUtil;                                                                                                                                                   
                                                                                                                                                                                        
public class DefaultRequestDispatcherImpl {                                                                                                                                             
  private static DefaultRequestDispatcherImpl defaultRequestDispatcher = new DefaultRequestDispatcherImpl();                                                                            
                                                                                                                                                                                        
  private static final long serialVersionUID = 12310091L;                                                                                                                               
                                                                                                                                                                                        
  private MultiPartResolver multiPartResolver;                                                                                                                                          
                                                                                                                                                                                        
  private Map dispatcherMap;                                                                                                                                                            
                                                                                                                                                                                        
  private Map extenstionMap;                                                                                                                                                            
                                                                                                                                                                                        
  private IPathMatcher patchMatcher;                                                                                                                                                    
                                                                                                                                                                                        
                                                                                                                                                                                        
  public static DefaultRequestDispatcherImpl getInstance() { return defaultRequestDispatcher; }                                                                                         
                                                                                                                                                                                        
                                                                                                                                                                                        
  private void init() {                                                                                                                                                                 
    System.err.println("Initialize WebSquare DefaultRequestDispatcher");                                                                                                                
    String customWq = WebSquareConfig.getInstance().getCustomWQ();                                                                                                                      
                                                                                                                                                                                        
    try {                                                                                                                                                                               
      if (WebSquareConfig.getInstance().supportUpload()) {                                                                                                                              
        String maxUploadSize = WebSquareConfig.getInstance().getMaxUploadSize();                                                                                                        
        long mus = 0L;                                                                                                                                                                  
        try {                                                                                                                                                                           
          mus = Long.parseLong(maxUploadSize);                                                                                                                                          
        } catch (Exception e) {                                                                                                                                                         
          mus = 1048576L;                                                                                                                                                               
        }                                                                                                                                                                               
        this.multiPartResolver = new MultiPartResolver(null, 5242880, mus);                                                                                                             
      }                                                                                                                                                                                 
    } catch (Exception e) {                                                                                                                                                             
      e.printStackTrace();                                                                                                                                                              
    } catch (Throwable e) {                                                                                                                                                             
      System.err.println("Upload library(commons-fileupload-1.2.jar) loading error occurred. If file upload wasn't needed, turn off file upload in configuration file(websquare.xml).");
      e.printStackTrace();                                                                                                                                                              
    }                                                                                                                                                                                   
    this.patchMatcher = new SimplePathMatcher();                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
    this.dispatcherMap = new LinkedHashMap();                                                                                                                                           
                                                                                                                                                                                        
    this.dispatcherMap.put("websquare.wq", new WebSquareController());                                                                                                                  
    this.dispatcherMap.put("javascript.wq", new JavascriptResourceController());                                                                                                        
    this.dispatcherMap.put("javascriptEngine.wq", new JavascriptEngineResourceController());                                                                                            
    this.dispatcherMap.put("javascriptPlugin.wq", new JavascriptPluginResourceController());                                                                                            
    this.dispatcherMap.put("javascriptPluginAll.wq", new JavascriptAllPluginResourceController());                                                                                      
    this.dispatcherMap.put("resource.wq", new ResourceController());                                                                                                                    
    this.dispatcherMap.put("xmlToExcel.wq", new GridToExcel());                                                                                                                         
                                                                                                                                                                                        
                                                                                                                                                                                        
    String versionString = System.getProperty("java.version").substring(0, 2);                                                                                                          
    double version = Double.parseDouble(versionString);                                                                                                                                 
                                                                                                                                                                                        
    if (version > 1.4D) {                                                                                                                                                               
      ClassLoader cl = Thread.currentThread().getContextClassLoader();                                                                                                                  
                                                                                                                                                                                        
      try {                                                                                                                                                                             
        Object customWqObj = null;                                                                                                                                                      
        if (!customWq.equals("")) {                                                                                                                                                     
          Class c = cl.loadClass(customWq);                                                                                                                                             
          customWqObj = c.newInstance();                                                                                                                                                
        }                                                                                                                                                                               
                                                                                                                                                                                        
        if (!customWq.equals("")) {                                                                                                                                                     
          this.dispatcherMap.put("wqDefiner.wq", customWqObj);                                                                                                                          
        }                                                                                                                                                                               
                                                                                                                                                                                        
        this.dispatcherMap.put("xmlToExcel2.wq", "");                                                                                                                                   
        this.dispatcherMap.put("excelToGrid2.wq", "");                                                                                                                                  
        this.dispatcherMap.put("chartToExcel.wq", "");                                                                                                                                  
        this.dispatcherMap.put("excelToJSON.wq", "");                                                                                                                                   
        this.dispatcherMap.put("textToJSON.wq", "");                                                                                                                                    
        this.dispatcherMap.put("pivotToExcel.wq", "");                                                                                                                                  
        this.dispatcherMap.put("pivotToCSV.wq", "");                                                                                                                                    
        this.dispatcherMap.put("excelToPivot.wq", "");                                                                                                                                  
        this.dispatcherMap.put("csvToPivot.wq", "");                                                                                                                                    
      }                                                                                                                                                                                 
      catch (Exception e) {                                                                                                                                                             
        e.printStackTrace();                                                                                                                                                            
      }                                                                                                                                                                                 
    }                                                                                                                                                                                   
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
    this.dispatcherMap.put("excelToGrid.wq", new ExcelToGrid());                                                                                                                        
    this.dispatcherMap.put("xmlToCSV.wq", new GridToCSV());                                                                                                                             
    this.dispatcherMap.put("csvToXML.wq", new CSVToGrid());                                                                                                                             
    this.dispatcherMap.put("upload.wq", new DefaultFileUploadController());                                                                                                             
    this.dispatcherMap.put("imageupload.wq", new DefaultImageFileUploadController());                                                                                                   
    this.dispatcherMap.put("delete.wq", new DefaultFileDeleteController());                                                                                                             
    this.dispatcherMap.put("preview.wq", new PreviewController());                                                                                                                      
    this.dispatcherMap.put("i18n.wq", new I18N());                                                                                                                                      
    this.dispatcherMap.put("serverTime.wq", new ServerTimeUtil());                                                                                                                      
    this.dispatcherMap.put("loadImg.wq", new LoadImg());                                                                                                                                
                                                                                                                                                                                        
    this.extenstionMap = new HashMap();                                                                                                                                                 
  }                                                                                                                                                                                     
                                                                                                                                                                                        
  public void init(ServletConfig config) throws ServletException {                                                                                                                      
    System.err.println("################INIT-POST-HANDLER###################");                                                                                                         
                                                                                                                                                                                        
                                                                                                                                                                                        
    Enumeration params = config.getInitParameterNames();                                                                                                                                
    while (params.hasMoreElements()) {                                                                                                                                                  
      String alias = (String)params.nextElement();                                                                                                                                      
                                                                                                                                                                                        
      String strClass = config.getInitParameter(alias);                                                                                                                                 
                                                                                                                                                                                        
      if (strClass == null || strClass.equals("") || alias.equals("WEBSQUARE_HOME")) {                                                                                                  
        continue;                                                                                                                                                                       
      }                                                                                                                                                                                 
      System.err.println(alias + ":" + strClass);                                                                                                                                       
                                                                                                                                                                                        
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();                                                                                                         
      int extensionIdx = alias.indexOf("#");                                                                                                                                            
      if (extensionIdx > -1) {                                                                                                                                                          
        String key = alias.substring(0, extensionIdx);                                                                                                                                  
        String extension = alias.substring(extensionIdx + 1);                                                                                                                           
        alias = key;                                                                                                                                                                    
        try {                                                                                                                                                                           
          Object object = this.dispatcherMap.get(alias);                                                                                                                                
          if (object == null) {                                                                                                                                                         
            System.err.println(alias + "-> IPostController is null");                                                                                                                   
            continue;                                                                                                                                                                   
          }                                                                                                                                                                             
          Class clazz = classLoader.loadClass(strClass);                                                                                                                                
          this.extenstionMap.put(alias, new Pair(extension, clazz)); continue;                                                                                                          
        } catch (Exception e) {                                                                                                                                                         
          e.printStackTrace(); continue;                                                                                                                                                
        }                                                                                                                                                                               
      }                                                                                                                                                                                 
      try {                                                                                                                                                                             
        Class clazz = classLoader.loadClass(strClass);                                                                                                                                  
        Object postHandler = clazz.newInstance();                                                                                                                                       
        if (postHandler instanceof IPostController) {                                                                                                                                   
          this.dispatcherMap.put(alias, postHandler); continue;                                                                                                                         
        }                                                                                                                                                                               
        System.err.println(postHandler.getClass().getName() + " must be IPostController");                                                                                              
      }                                                                                                                                                                                 
      catch (Exception e) {                                                                                                                                                             
        e.printStackTrace();                                                                                                                                                            
      }                                                                                                                                                                                 
    }                                                                                                                                                                                   
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
  class Pair                                                                                                                                                                            
  {                                                                                                                                                                                     
    String method;                                                                                                                                                                      
    Class c;                                                                                                                                                                            
                                                                                                                                                                                        
    public Pair(String method, Class c) {                                                                                                                                               
      this.method = "set" + String.valueOf(method.charAt(0)).toUpperCase() + method.substring(1);                                                                                       
      this.c = c;                                                                                                                                                                       
    }                                                                                                                                                                                   
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
  private DefaultRequestDispatcherImpl() { init(); }                                                                                                                                    
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
  public final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {                                                            
    try {                                                                                                                                                                               
      doDispatch(request, response);                                                                                                                                                    
    }                                                                                                                                                                                   
    catch (Exception e) {                                                                                                                                                               
      String message = null;                                                                                                                                                                   
      if (request.getRequestURI().indexOf("javascript") > -1) {                                                                                                                         
        message = ";";                                                                                                                                                                  
        response.setContentType(MimeUtil.getMimeTypeFromExt("js"));                                                                                                                     
      } else {                                                                                                                                                                          
        message = "<Exception>UnKnown Error..</Exception>";                                                                                                                             
        response.setContentType(MimeUtil.getMimeTypeFromExt("xml") + "; charset=" + "UTF-8");                                                                                           
      }                                                                                                                                                                                 
      if (!(e instanceof PostControllerException)) {                                                                                                                                    
        LogUtil.exception("[DefaultRequestDispatcherImpl.service] UnKnown Error", e);                                                                                                   
      } else {                                                                                                                                                                          
        PostControllerException pe = (PostControllerException)e;                                                                                                                        
        message = pe.getMessage();                                                                                                                                                      
      }                                                                                                                                                                                 
      ServletOutputStream os = response.getOutputStream();                                                                                                                              
      os.write(message.getBytes("UTF-8"));                                                                                                                                              
    } finally {                                                                                                                                                                         
      ServletOutputStream os = response.getOutputStream();                                                                                                                              
      if (os != null) {                                                                                                                                                                 
        try {                                                                                                                                                                           
          os.flush();                                                                                                                                                                   
        } catch (IOException iOException) {}                                                                                                                                            
      }                                                                                                                                                                                 
    }                                                                                                                                                                                   
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
  public final void doDispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, Exception {                                                         
    HttpServletRequest internalRequest = request;                                                                                                                                       
                                                                                                                                                                                        
    LogUtil.config("Start Request : " + request.getRequestURI() + "?" + request.getQueryString());                                                                                      
                                                                                                                                                                                        
    IPostController postController = null;                                                                                                                                              
    try {                                                                                                                                                                               
      if ("post".equals(request.getMethod().toLowerCase())) {                                                                                                                           
        String contentType = request.getContentType();                                                                                                                                  
        if (contentType != null && contentType.toLowerCase().startsWith("multipart/")) {                                                                                                
          if (this.multiPartResolver != null) {                                                                                                                                         
            internalRequest = this.multiPartResolver.resolveMultipart(request);                                                                                                         
          } else {                                                                                                                                                                      
            LogUtil.severe("[DefaultRequestDispatcherImpl.doDispatch] multipartResolver is null...");                                                                                   
            return;                                                                                                                                                                     
          }                                                                                                                                                                             
        } else {                                                                                                                                                                        
          internalRequest = request;                                                                                                                                                    
        }                                                                                                                                                                               
      }                                                                                                                                                                                 
                                                                                                                                                                                        
                                                                                                                                                                                        
      WebSquareContext websquareContext = WebSquareContext.getContext();                                                                                                                
      websquareContext.setWebInfo(internalRequest, response, null, null);                                                                                                               
                                                                                                                                                                                        
      postController = lookupPostHandler(internalRequest);                                                                                                                              
                                                                                                                                                                                        
      if (postController != null) {                                                                                                                                                     
        if (postController instanceof websquare.document.IWebSquareDocument) {                                                                                                          
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
          postController = (IPostController)postController.getClass().newInstance();                                                                                                    
          String key = findKey(internalRequest);                                                                                                                                        
          Object object = this.extenstionMap.get(key);                                                                                                                                  
          if (object != null) {                                                                                                                                                         
            Pair p = (Pair)object;                                                                                                                                                      
            Method method = postController.getClass().getMethod(p.method, new Class[] { Object.class });                                                                                
            if (method != null) {                                                                                                                                                       
              method.invoke(postController, new Object[] { p.c.newInstance() });                                                                                                        
            }                                                                                                                                                                           
          }                                                                                                                                                                             
        }                                                                                                                                                                               
        postController.doHandle(internalRequest, new WebSquareResponseWrapper(response));                                                                                               
      }                                                                                                                                                                                 
    } finally {                                                                                                                                                                         
                                                                                                                                                                                        
      if (postController != null &&                                                                                                                                                     
        postController instanceof IDisposable) {                                                                                                                                        
        ((IDisposable)postController).dispose();                                                                                                                                        
      }                                                                                                                                                                                 
                                                                                                                                                                                        
                                                                                                                                                                                        
      if (internalRequest != request && internalRequest instanceof MultiPartHttpServletRequest && isCleanup((MultiPartHttpServletRequest)internalRequest)) {                            
                                                                                                                                                                                        
        MultiPartHttpServletRequest mr = (MultiPartHttpServletRequest)internalRequest;                                                                                                  
        Collection values = mr.getMultipartFiles().values();                                                                                                                            
        if (this.multiPartResolver != null) {                                                                                                                                           
          this.multiPartResolver.cleanupFileItems(values);                                                                                                                              
        } else {                                                                                                                                                                        
          LogUtil.severe("[DefaultRequestDispatcherImpl.doDispatch] multipartResolver is null...");                                                                                     
        }                                                                                                                                                                               
                                                                                                                                                                                        
        LogUtil.config("cleanup done.");                                                                                                                                                
      }                                                                                                                                                                                 
                                                                                                                                                                                        
      LogUtil.config("End Request : " + request.getRequestURI() + "?" + request.getQueryString());                                                                                      
    }                                                                                                                                                                                   
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
  public Map getDispatcherMap() { return new LinkedHashMap(this.dispatcherMap); }                                                                                                       
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
  protected boolean isCleanup(MultiPartHttpServletRequest internalRequest) {                                                                                                            
    Map multipartParameters = internalRequest.getMultipartParameters();                                                                                                                 
    String uploadClean = (String)multipartParameters.get("uploadClean");                                                                                                                
    if (uploadClean == null || !uploadClean.equals("true")); return true;                                                                                                               
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
                                                                                                                                                                                        
  protected IPostController lookupPostHandler(HttpServletRequest request) {                                                                                                             
    try {                                                                                                                                                                               
      String servletPath = request.getServletPath();                                                                                                                                    
      if (servletPath == null || !servletPath.endsWith(".wq")) {                                                                                                                        
        servletPath = request.getRequestURI();                                                                                                                                          
      }                                                                                                                                                                                 
      String key = null;                                                                                                                                                                
      Iterator dispatcherKeys = this.dispatcherMap.keySet().iterator();                                                                                                                 
      while (dispatcherKeys.hasNext()) {                                                                                                                                                
        key = (String)dispatcherKeys.next();                                                                                                                                            
        if (this.patchMatcher != null &&                                                                                                                                                
          this.patchMatcher.match(key, servletPath))                                                                                                                                    
        {                                                                                                                                                                               
          ClassLoader cl = Thread.currentThread().getContextClassLoader();                                                                                                              
                                                                                                                                                                                        
          IPostController postObj = null;                                                                                                                                               
          if (key.equals("xmlToExcel2.wq")) {                                                                                                                                           
            Class c = cl.loadClass("websquare.http.controller.grid.excel.write.GridToExcel2");                                                                                          
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("excelToGrid2.wq")) {                                                                                                                                   
            Class c = cl.loadClass("websquare.http.controller.grid.excel.read.AdvancedExcelToGrid");                                                                                    
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("chartToExcel.wq")) {                                                                                                                                   
            Class c = cl.loadClass("websquare.http.controller.chart.ChartToExcel");                                                                                                     
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("excelToJSON.wq")) {                                                                                                                                    
            Class c = cl.loadClass("websquare.http.controller.grid.excel.read.ExcelToJSON");                                                                                            
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("textToJSON.wq")) {                                                                                                                                     
            Class c = cl.loadClass("websquare.http.controller.grid.text.read.TextToJSON");                                                                                              
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("pivotToExcel.wq")) {                                                                                                                                   
            Class c = cl.loadClass("websquare.http.controller.pivot.excel.write.PivotToExcel");                                                                                         
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("pivotToCSV.wq")) {                                                                                                                                     
            Class c = cl.loadClass("websquare.http.controller.pivot.text.write.PivotToCSV");                                                                                            
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("excelToPivot.wq")) {                                                                                                                                   
            Class c = cl.loadClass("websquare.http.controller.pivot.excel.read.ExcelToPivot");                                                                                          
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else if (key.equals("csvToPivot.wq")) {                                                                                                                                     
            Class c = cl.loadClass("websquare.http.controller.pivot.text.read.CSVToPivot");                                                                                             
            postObj = (IPostController)c.newInstance();                                                                                                                                 
          } else {                                                                                                                                                                      
            postObj = (IPostController)this.dispatcherMap.get(key);                                                                                                                     
          }                                                                                                                                                                             
                                                                                                                                                                                        
          return postObj;                                                                                                                                                               
        }                                                                                                                                                                               
                                                                                                                                                                                        
      }                                                                                                                                                                                 
    } catch (Exception exception) {}                                                                                                                                                    
                                                                                                                                                                                        
                                                                                                                                                                                        
    return null;                                                                                                                                                                        
  }                                                                                                                                                                                     
                                                                                                                                                                                        
  protected String findKey(HttpServletRequest request) {                                                                                                                                
    String servletPath = request.getServletPath();                                                                                                                                      
    if (servletPath == null || !servletPath.endsWith(".wq")) {                                                                                                                          
      servletPath = request.getRequestURI();                                                                                                                                            
    }                                                                                                                                                                                   
    String key = null;                                                                                                                                                                  
    Iterator dispatcherKeys = this.dispatcherMap.keySet().iterator();                                                                                                                   
    while (dispatcherKeys.hasNext()) {                                                                                                                                                  
      key = (String)dispatcherKeys.next();                                                                                                                                              
      if (this.patchMatcher != null &&                                                                                                                                                  
        this.patchMatcher.match(key, servletPath)) {                                                                                                                                    
        return key;                                                                                                                                                                     
      }                                                                                                                                                                                 
    }                                                                                                                                                                                   
                                                                                                                                                                                        
    return null;                                                                                                                                                                        
  }                                                                                                                                                                                     
                                                                                                                                                                                        
  public void addDispatcherMap(Map dispatcherMap) {                                                                                                                                     
    Iterator iterator = this.dispatcherMap.keySet().iterator();                                                                                                                         
    while (iterator.hasNext()) {                                                                                                                                                        
      String itr = (String)iterator.next();                                                                                                                                             
      if (!dispatcherMap.containsKey(itr)) {                                                                                                                                            
        this.dispatcherMap.put(itr, dispatcherMap.get(itr)); continue;                                                                                                                  
      }                                                                                                                                                                                 
      LogUtil.info("[DefaultRequestDispatcherImpl.addDispatcherMap] ignored key : " + itr);                                                                                             
    }                                                                                                                                                                                   
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
  public void addDispatcherMap(String key, IPostController controller) {                                                                                                                
    if (key == null || key.equals("")) {                                                                                                                                                
      LogUtil.info("[DefaultRequestDispatcherImpl.addDispatcherMap] null key");                                                                                                         
    } else if (!this.dispatcherMap.containsKey(key)) {                                                                                                                                  
      this.dispatcherMap.put(key, controller);                                                                                                                                          
    } else {                                                                                                                                                                            
      LogUtil.info("[DefaultRequestDispatcherImpl.addDispatcherMap] ignored key : " + key);                                                                                             
    }                                                                                                                                                                                   
  }                                                                                                                                                                                     
                                                                                                                                                                                        
                                                                                                                                                                                        
  public void setPatchMatcher(IPathMatcher patchMatcher) { this.patchMatcher = patchMatcher; }                                                                                          
}                                                                                                                                                                                       