package refactoring.struts; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectOutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.struts.config.ActionConfig; import org.apache.struts.config.ExceptionConfig; import org.apache.struts.config.FormBeanConfig; import org.apache.struts.config.ForwardConfig; import org.apache.struts.config.ModuleConfig; import refactoring.struts.ActionServletPlaceholder.ConfigPlaceholder; import refactoring.struts.beans.FormBean; import refactoring.struts.beans.ForwardAnnotationBean; import refactoring.struts.beans.MappingAnnotationBean; import refactoring.struts.beans.SyntheticDispatchAction; public class RefactorStart { public static void main(String[] args) throws Exception { startParsingStruts(); } public static List startParsingStruts() throws Exception { ConfigPlaceholder config = ActionServletPlaceholder.getConfigFilesWrapper(); Enumeration paramNames = config.getInitParameterNames(); List moduleConfigs = new ArrayList(); String paramName = ""; String paramValue = config.getInitParameter("config"); String prefix = ""; ModuleConfig mc = ActionServletPlaceholder.initModuleConfig(prefix, paramValue); mc.freeze(); moduleConfigs.add(new ModuleAnnotations(mc)); System.out.println("Key: " + paramName + "\nValue: " + paramValue + "\n"); while (paramNames.hasMoreElements()) { paramName = paramNames.nextElement(); paramValue = config.getInitParameter(paramName); /* * FIXME the struts ActionServlet ignores anything without start * config/ However, that excludes our default config file. The * ActionServlet assumes a nameless module, "", with respective file * being in "/WEB-INF/struts-config.xml" which is not the case of * fenix */ /* * NOTE we have the fenix project in the classpath because we need * classes over there, namely for mappings and for formbeans fields' * types */ if (!paramName.startsWith("config/")) { continue; } System.out.println("Key: " + paramName + "\nValue: " + paramValue + "\n"); prefix = paramName.substring(6); mc = ActionServletPlaceholder.initModuleConfig(prefix, paramValue); mc.freeze(); moduleConfigs.add(new ModuleAnnotations(mc)); } Iterator iter = moduleConfigs.iterator(); while (iter.hasNext()) { ModuleAnnotations moduleAnnotations = iter.next(); ModuleConfig moduleConfig = moduleAnnotations.getModuleConfig(); if (moduleConfig.getPrefix().equals("/masterDegreeCandidate")) { System.out.println("#-------------#\nSkipped masterDegreeCandidate"); continue; } if (moduleConfig.getPrefix().equals("/external")) { System.out.println("#-------------#\nSkipped external"); continue; } } for (ModuleAnnotations moduleAnnotations : moduleConfigs) { ModuleConfig moduleConfig = moduleAnnotations.getModuleConfig(); System.out.println("#-----------------#\nNew module: " + moduleConfig.getPrefix()); List createdFormBeans = new ArrayList(); for (FormBeanConfig formBeanConfig : moduleConfig.findFormBeanConfigs()) { /* * System.out.println("----->Form bean of: " + * moduleConfig.getPrefix() + "\tdynamic? " + * formBeanConfig.getDynamic() + "\n"); */ /* * if (formBeanConfig.getDynamic()) { * createdFormBeans.add(FormBeanCreator * .createFormBean(formBeanConfig, moduleConfig.getPrefix())); } */ } moduleAnnotations.setCreatedFormBeans(createdFormBeans); LogMissingDispatchAction missingLog = new LogMissingDispatchAction(); for (ActionConfig actionConfig : moduleConfig.findActionConfigs()) { MappingAnnotationBean mappingBean = ActionMappingCreator.createActionMapping(moduleConfig.getPrefix(), actionConfig, missingLog); if (mappingBean == null) { continue; } for (ExceptionConfig exceptionConfig : actionConfig.findExceptionConfigs()) { ExceptionsCreator.createException(exceptionConfig, mappingBean); } for (ForwardConfig forwardConfig : actionConfig.findForwardConfigs()) { ForwardCreator.createForward(forwardConfig, mappingBean); } if (!mappingBean.isDAalreadyContainsMapping()) { moduleAnnotations.addMappingAnnotation(mappingBean); } } moduleAnnotations.setMissingDAs(missingLog); } StrutsStats.produceStatistics(moduleConfigs); removeMappingsMustSkipTiles(moduleConfigs); /* * Create dispatch actions that result from inter module conflicts If * they do not exist already */ for (ModuleAnnotations ma : moduleConfigs) { Set classesToCreate = new HashSet(); for (MappingAnnotationBean mapping : ma.getInterModuleConflictMappings()) { classesToCreate.add(mapping.getDispatchActionClassName()); } for (String daNew : classesToCreate) { String moduleName = (isEmpty(ma.getModulePrefix()) ? "defaultModule" : ma.getModulePrefix()); SyntheticDispatchAction result = DispatchActionCreator.createDispatchAction(moduleName, daNew); System.out.println("Module: " + moduleName + " wrote new DA: " + result.getFilePath()); for (MappingAnnotationBean mapping : ma.getInterModuleConflictMappings()) { if (mapping.getDispatchActionClassName().equals(daNew)) { mapping.setNewDAName(result.getQualifiedClassName()); mapping.setNewDAFile(result.getFilePath()); } } FileInputStream fis; InputStreamReader isr = null; StringBuilder dispatchActionSourceCode = new StringBuilder(); boolean alreadyExists = false; try { fis = new FileInputStream(new File(result.getFilePath())); isr = new InputStreamReader(fis, Charset.forName("ISO-8859-1")); while (isr.ready()) { dispatchActionSourceCode.append((char) isr.read()); } alreadyExists = true; } catch (FileNotFoundException e) { alreadyExists = false; } catch (IOException e) { e.printStackTrace(); System.exit(0); } finally { if (isr != null) { try { isr.close(); } catch (IOException e) { e.printStackTrace(); System.exit(0); } } } if (alreadyExists) { continue; } FileOutputStream fos; OutputStreamWriter osw = null; try { File newFile = new File(result.getFilePath()); newFile.getParentFile().mkdirs(); fos = new FileOutputStream(newFile); osw = new OutputStreamWriter(fos, Charset.forName("ISO-8859-1")); osw.write(result.getSourceCode()); } catch (FileNotFoundException e) { e.printStackTrace(); System.exit(0); } catch (IOException e) { e.printStackTrace(); System.exit(0); } finally { try { if (osw != null) { osw.flush(); osw.close(); } } catch (IOException e) { e.printStackTrace(); System.exit(0); } } } } /* * Send the data to the plugin (already launched and waiting on socket) */ Socket mClientSocket = null; try { mClientSocket = new Socket("localhost", 10001); ObjectOutputStream out = new ObjectOutputStream(mClientSocket.getOutputStream()); out.writeObject("struts"); out.writeObject(moduleConfigs); } finally { mClientSocket.close(); } return moduleConfigs; } private static void removeMappingsMustSkipTiles(List moduleConfigs) { StringBuilder result = new StringBuilder(); int totalAffected = 0; int totalOverall = 0; for (ModuleAnnotations ma : moduleConfigs) { int totalMappingsAffected = 0; Iterator annotationIter = ma.getMappingAnnotations().iterator(); while (annotationIter.hasNext()) { MappingAnnotationBean mappingBean = annotationIter.next(); if (checkIfShouldSkip(mappingBean)) { totalMappingsAffected++; annotationIter.remove(); } } annotationIter = ma.getInterModuleConflictMappings().iterator(); while (annotationIter.hasNext()) { MappingAnnotationBean mappingBean = annotationIter.next(); if (checkIfShouldSkip(mappingBean)) { totalMappingsAffected++; annotationIter.remove(); } } result.append("Module "); result.append(ma.getModuleConfig().getPrefix()); result.append(" "); result.append(totalMappingsAffected); result.append(" mappings affected"); totalAffected += totalMappingsAffected; int localOverall = ma.getMappingAnnotations().size() + ma.getInterModuleConflictMappings().size(); result.append(" still have "); result.append(localOverall); result.append("\n"); totalOverall += localOverall; } System.out.println(result + "\nTotal: " + totalAffected + " remaining " + totalOverall); } private static boolean checkIfShouldSkip(MappingAnnotationBean mappingBean) { String input = mappingBean.getInput(); if (!isEmpty(input) && shouldBeSkipped(input)) { return true; } String mappingPath = mappingBean.getPath(); if (!isEmpty(mappingPath) && shouldBeSkipped(mappingPath + ".do")) { return true; } for (ForwardAnnotationBean forwardBean : mappingBean.getForwardList()) { String forwardPath = forwardBean.getPath(); if (!isEmpty(forwardPath) && shouldBeSkipped(forwardPath)) { return true; } } return false; } public static boolean isEmpty(String str) { if (str == null) { return true; } return str.isEmpty(); } private static boolean shouldBeSkipped(String path) { return path.contains("/CSS/") || path.contains("/javaScript/") || path.endsWith(".jsp") || path.contains("images/") || path.contains("/checkPasswordKerberos.do") || path.contains("/loginCAS.do") || path.contains("/ajax/") || path.contains("/checkPasswordKerberos.do") || path.contains("/loginCAS.do") || path.endsWith("/redirect.do") || path.endsWith("/userDoesNotExistOrIsInactive.do") || path.contains("/home.do") || path.contains("/logoff.do") || path.contains("/siteMap.do") || path.contains("/login.do") || path.startsWith("/external/") || path.startsWith("/isAlive.do") || path.endsWith(".html") || path.endsWith(".htm") || path.startsWith("/exceptionHandlingAction.do") || path.startsWith("/showErrorPageRegistered.do") || path.startsWith("/services") || path.contains("/loginExpired.do") || path.contains("/summariesRSS.do") || path.startsWith("/gwt") || path.startsWith("/remote"); } /* * Form bean classes reconstruction takes into account: for each * ActionMapping, if we have the name property defined, then that's the name * of the bean. thus we use moduleConfig.findFormBeanConfig(thatname) and * get the FormBeanConfig. then we open the file that corresponds to the * class of the dispatch action of this ActionMapping, by using the type * property of this ActionMapping. In that file, we have to programatically * write the source code corresponding to the FormBeanConfig acquired. * * Alternatively, we can create the FormBean independently in a .java, and * import it in the DispatchAction acquired with the type of the * ActionMapping, and then add to the @Mapping that will be created, the * formBeanClass=thatclass.class */ private static void printMissingLog(Map missingLogs) { System.out.println("##############Missing log###############"); for (Map.Entry moduleLog : missingLogs.entrySet()) { StringBuilder DAsMissing = new StringBuilder(); for (Map.Entry> missesLog : moduleLog.getValue().getLoggedMappings().entrySet()) { DAsMissing.append(missesLog.getKey() + " | "); } System.out.println("-->Log of module: " + moduleLog.getKey().getPrefix() + " ---> missing files: " + DAsMissing.toString()); } } }