sysmodelmgr/com.symbian.smt.gui/src/com/symbian/smt/gui/builder/SMTCommand.java
changeset 0 522a326673b6
equal deleted inserted replaced
-1:000000000000 0:522a326673b6
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 package com.symbian.smt.gui.builder;
       
    17 
       
    18 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.BORDER_SHAPES_FILES;
       
    19 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.BORDER_STYLES_FILES;
       
    20 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.COLOURS_FILES;
       
    21 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.COPYRIGHT_TEXT;
       
    22 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.DEPENDENCIES_FILES;
       
    23 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.DISTRIBUTION_TEXT;
       
    24 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.FILTER_HAS_ITEMS;
       
    25 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.FIX_ITEM_SIZE;
       
    26 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.HIGHTLIGHT_CORE_OS;
       
    27 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.IGNORE_ITEMS;
       
    28 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.LEVELS_FILES;
       
    29 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.LEVEL_OF_DETAIL;
       
    30 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.LOCALISATION_FILES;
       
    31 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.MODEL_NAME;
       
    32 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.MODEL_VERSION;
       
    33 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.MODEL_VERSION_TEXT;
       
    34 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.OUTPUT_FILE;
       
    35 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.PATTERNS_FILES;
       
    36 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.PRINTED_DPI;
       
    37 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.S12_XML_FILES;
       
    38 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SHAPES_FILES;
       
    39 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SUPPRESS_MOUSE_OVER_EFFECT;
       
    40 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_DEFINITION_FILES;
       
    41 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_INFO_FILES;
       
    42 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_NAME;
       
    43 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_VERSION;
       
    44 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.TEMPDIR;
       
    45 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.WARNING_LEVEL;
       
    46 
       
    47 import java.io.File;
       
    48 import java.io.IOException;
       
    49 import java.util.ArrayList;
       
    50 import java.util.List;
       
    51 import java.util.Locale;
       
    52 import java.util.ResourceBundle;
       
    53 import java.util.regex.Matcher;
       
    54 import java.util.regex.Pattern;
       
    55 
       
    56 import javax.xml.parsers.ParserConfigurationException;
       
    57 
       
    58 import org.eclipse.core.resources.IFolder;
       
    59 import org.eclipse.core.resources.IProject;
       
    60 import org.eclipse.core.resources.ProjectScope;
       
    61 import org.eclipse.core.runtime.preferences.DefaultScope;
       
    62 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
       
    63 import org.eclipse.core.runtime.preferences.IScopeContext;
       
    64 import org.eclipse.core.runtime.preferences.InstanceScope;
       
    65 import org.eclipse.swt.widgets.Display;
       
    66 import org.xml.sax.SAXException;
       
    67 
       
    68 import com.symbian.smt.gui.Activator;
       
    69 import com.symbian.smt.gui.Logger;
       
    70 import com.symbian.smt.gui.PersistentDataStore;
       
    71 import com.symbian.smt.gui.SystemDefinition;
       
    72 import com.symbian.smt.gui.SystemDefinitionValidationException;
       
    73 import com.symbian.smt.gui.SystemDefinitionValidationFatalException;
       
    74 import com.symbian.smt.gui.views.ConsoleOutput;
       
    75 
       
    76 public class SMTCommand {
       
    77 
       
    78 	private static String SMG_FOLDER = ""; // The location of the System Model
       
    79 											// Generator
       
    80 	private static String SMT_COMMAND = ""; // The perl script to run for the
       
    81 											// System Model Generator
       
    82 	final static String TEMP_FOLDER = ".svg_temp"; // Folder names stating with
       
    83 													// a . will not be displayed
       
    84 													// in the project navigator
       
    85 	private IFolder svgTempFolder;
       
    86 	private IProject project;
       
    87 	private ArrayList<String> command = new ArrayList<String>();;
       
    88 
       
    89 	private PersistentDataStore defaultStore;
       
    90 	private PersistentDataStore instanceStore;
       
    91 	private PersistentDataStore projectStore;
       
    92 
       
    93 	private Pattern ampersandPattern = Pattern.compile("&",
       
    94 			Pattern.CASE_INSENSITIVE);
       
    95 	private Pattern lessThanPattern = Pattern.compile("<",
       
    96 			Pattern.CASE_INSENSITIVE);
       
    97 	private Pattern greaterThanPattern = Pattern.compile(">",
       
    98 			Pattern.CASE_INSENSITIVE);
       
    99 	private Pattern singleQuotePattern = Pattern.compile("'",
       
   100 			Pattern.CASE_INSENSITIVE);
       
   101 	private Pattern doubleQuotePattern = Pattern.compile("\"",
       
   102 			Pattern.CASE_INSENSITIVE);
       
   103 
       
   104 	public SMTCommand(IProject project) {
       
   105 		this.project = project;
       
   106 		svgTempFolder = project.getFolder(TEMP_FOLDER);
       
   107 
       
   108 		final ResourceBundle resourceBundle = ResourceBundle.getBundle(
       
   109 				"location", Locale.getDefault(), this.getClass()
       
   110 						.getClassLoader());
       
   111 
       
   112 		SMG_FOLDER = resourceBundle.getString("location");
       
   113 
       
   114 		try {
       
   115 			SMT_COMMAND = new File(SMG_FOLDER + File.separator + "SysModGen.pl")
       
   116 					.getCanonicalPath();
       
   117 		} catch (IOException e) {
       
   118 			Logger.log(e.getMessage(), e);
       
   119 		}
       
   120 	}
       
   121 
       
   122 	/**
       
   123 	 * Generates the command line string for the System Model Toolkit
       
   124 	 * 
       
   125 	 * @return List<String> Arguments for the CLI
       
   126 	 */
       
   127 	public List<String> generateCommand() {
       
   128 		// Set up access to the persistent data stores
       
   129 		IScopeContext defaultScope = new DefaultScope();
       
   130 		IEclipsePreferences defaultNode = defaultScope
       
   131 				.getNode(Activator.PLUGIN_ID);
       
   132 		defaultStore = new PersistentDataStore(defaultNode);
       
   133 
       
   134 		IScopeContext instanceScope = new InstanceScope();
       
   135 		IEclipsePreferences instanceNode = instanceScope
       
   136 				.getNode(Activator.PLUGIN_ID);
       
   137 		instanceStore = new PersistentDataStore(instanceNode, defaultNode);
       
   138 
       
   139 		IScopeContext projectScope = new ProjectScope(project);
       
   140 		IEclipsePreferences projectNode = projectScope
       
   141 				.getNode(Activator.PLUGIN_ID);
       
   142 		projectStore = new PersistentDataStore(projectNode);
       
   143 
       
   144 		// Required to use the SMT script
       
   145 		command.add("perl");
       
   146 		command.add(SMT_COMMAND);
       
   147 
       
   148 		// Add the system definition files
       
   149 		String[] sysDefFiles = projectStore.getSystemDefinitionFiles();
       
   150 		
       
   151 		// The while loop below protects against concurrency conditions which
       
   152 		// are encountered when the sys def file is a URL resource and
       
   153 		// when we are creating a new project via the NewSMTProjectWizard.
       
   154 		while (sysDefFiles.length == 0) {
       
   155 			try {
       
   156 				Thread.sleep(10);
       
   157 			} catch (InterruptedException ignore) {
       
   158 			}
       
   159 			
       
   160 			sysDefFiles = projectStore.getSystemDefinitionFiles();
       
   161 		}
       
   162 
       
   163 		command.add(SYSTEM_DEFINITION_FILES.arg());
       
   164 
       
   165 		// Check that the system definition files are valid
       
   166 		// Only fatal errors cause the build attempt to be aborted.
       
   167 		//
       
   168 		for (String filename : sysDefFiles) {
       
   169 			try {
       
   170 				SystemDefinition.checkValidSystemDefinitionFile(filename);
       
   171 			} catch (SystemDefinitionValidationFatalException e1) {
       
   172 				writeToConsoleOutput("Error: " + filename
       
   173 						+ " is not a valid system definition file:\n"
       
   174 						+ e1.getMessage());
       
   175 				Logger.log("Validation of system definition file ("+filename+") failed.", e1);
       
   176 				return null;
       
   177 			} catch (SystemDefinitionValidationException e1) {
       
   178 				Logger.log("Validation of system definition file ("+filename+") failed.", e1);
       
   179 			} 
       
   180 		}
       
   181 
       
   182 		// There may be multiple system definition files, if there are they need
       
   183 		// to be joined with a ,
       
   184 		if (sysDefFiles.length == 1) {
       
   185 			command.add(prepareArg(sysDefFiles[0]));
       
   186 		} else {
       
   187 			StringBuilder sysDefJoined = new StringBuilder();
       
   188 
       
   189 			for (String file : sysDefFiles) {
       
   190 				sysDefJoined.append(file);
       
   191 				sysDefJoined.append(",");
       
   192 			}
       
   193 
       
   194 			command.add(prepareArg(sysDefJoined.toString()));
       
   195 		}
       
   196 
       
   197 		// Add the resources
       
   198 		// Default files in this context mean file the user selected
       
   199 		handleResource(SHAPES_FILES, projectStore.getSelectedShapesFiles());
       
   200 		handleResource(LEVELS_FILES, projectStore.getSelectedLevelsFiles());
       
   201 		handleResource(SYSTEM_INFO_FILES, projectStore
       
   202 				.getSelectedSystemInfoFiles());
       
   203 		handleResource(DEPENDENCIES_FILES, projectStore
       
   204 				.getSelectedDependenciesFiles());
       
   205 		handleResource(COLOURS_FILES, projectStore.getSelectedColoursFiles());
       
   206 		handleResource(BORDER_SHAPES_FILES, projectStore
       
   207 				.getSelectedBorderShapesFiles());
       
   208 		handleResource(PATTERNS_FILES, projectStore.getSelectedPatternsFiles());
       
   209 		handleResource(LOCALISATION_FILES, projectStore
       
   210 				.getSelectedLocalisationFiles());
       
   211 		handleResource(BORDER_STYLES_FILES, projectStore
       
   212 				.getSelectedBorderStylesFiles());
       
   213 		handleResource(S12_XML_FILES, projectStore.getSelectedS12XmlFiles());
       
   214 
       
   215 		// Add the model labels
       
   216 		command.add(COPYRIGHT_TEXT.arg());
       
   217 		command.add(prepareArg(projectStore.getCopyrightText()));
       
   218 
       
   219 		command.add(SYSTEM_NAME.arg());
       
   220 		command.add(prepareArg(projectStore.getSystemName()));
       
   221 
       
   222 		command.add(DISTRIBUTION_TEXT.arg());
       
   223 		command.add(prepareArg(projectStore.getSelectedDistributionText()));
       
   224 
       
   225 		command.add(MODEL_NAME.arg());
       
   226 		command.add(prepareArg(projectStore.getModelName()));
       
   227 
       
   228 		command.add(MODEL_VERSION.arg());
       
   229 		command.add(prepareArg(projectStore.getModelVersion()));
       
   230 
       
   231 		command.add(MODEL_VERSION_TEXT.arg());
       
   232 		command.add(prepareArg(projectStore.getSelectedModelVersionText()));
       
   233 
       
   234 		command.add(SYSTEM_VERSION.arg());
       
   235 		command.add(prepareArg(projectStore.getSystemVersion()));
       
   236 
       
   237 		// Add the model control settings
       
   238 		command.add(HIGHTLIGHT_CORE_OS.arg());
       
   239 		if (projectStore.getHighlightCoreOS().toString().equalsIgnoreCase(
       
   240 				"true")) {
       
   241 			command.add("on");
       
   242 		} else {
       
   243 			command.add("false");
       
   244 		}
       
   245 
       
   246 		command.add(LEVEL_OF_DETAIL.arg());
       
   247 		command.add(prepareArg(projectStore.getLevelOfDetail()));
       
   248 
       
   249 		String dpi = projectStore.getSelectedPrintedDpi();
       
   250 
       
   251 		// The dpi option is to be added only if the user
       
   252 		// selected or typed in an option other than ""
       
   253 		if ((dpi != null) && (!dpi.equals(""))) {
       
   254 			command.add(PRINTED_DPI.arg());
       
   255 			command.add(prepareArg(dpi));
       
   256 		}
       
   257 
       
   258 		if (projectStore.getSuppressMouseOverEffect()) {
       
   259 			command.add(SUPPRESS_MOUSE_OVER_EFFECT.arg());
       
   260 		}
       
   261 
       
   262 		// The fix item size option is to be added only if the user
       
   263 		// checked the corresponding check box
       
   264 		if (projectStore.getFixItemSize()) {
       
   265 			command.add(FIX_ITEM_SIZE.arg());
       
   266 			command.add("fixed");
       
   267 		}
       
   268 
       
   269 		// Filter has Items
       
   270 		command.add(FILTER_HAS_ITEMS.arg());
       
   271 
       
   272 		String[] filterHasItems = projectStore.getFilterHasItems();
       
   273 
       
   274 		// No command line argument if there are no filter-has keywords
       
   275 		// If there are multiple filter has items, they need to be joined with a
       
   276 		// ,
       
   277 		if (filterHasItems.length > 0) {
       
   278 			if (filterHasItems.length == 1) {
       
   279 				command.add(prepareArg(filterHasItems[0]));
       
   280 			} else {
       
   281 				StringBuilder filterItemsJoined = new StringBuilder();
       
   282 
       
   283 				for (String filter : filterHasItems) {
       
   284 					filterItemsJoined.append(filter);
       
   285 					filterItemsJoined.append(",");
       
   286 				}
       
   287 
       
   288 				filterItemsJoined.deleteCharAt(filterItemsJoined.length() - 1);
       
   289 				command.add(prepareArg(filterItemsJoined.toString()));
       
   290 			}
       
   291 		}
       
   292 
       
   293 		// Ignore Items
       
   294 		List<String[]> ignoreItems = projectStore.getIgnoreItems();
       
   295 
       
   296 		StringBuilder ignoreItemsJoined = new StringBuilder();
       
   297 
       
   298 		for (String[] ignoreItem : ignoreItems) {
       
   299 			ignoreItemsJoined.append(ignoreItem[0]);
       
   300 			ignoreItemsJoined.append(":");
       
   301 			ignoreItemsJoined.append(ignoreItem[1]);
       
   302 			ignoreItemsJoined.append(";");
       
   303 		}
       
   304 
       
   305 		command.add(IGNORE_ITEMS.arg());
       
   306 		command.add(prepareArg(ignoreItemsJoined.toString()));
       
   307 
       
   308 		// Set the temp folder to use
       
   309 		command.add(TEMPDIR.arg());
       
   310 		command.add(prepareArg(svgTempFolder.getLocation().toString()));
       
   311 
       
   312 		// Set the warning level
       
   313 		command.add(WARNING_LEVEL.arg());
       
   314 		command.add(instanceStore.getWarningLevel());
       
   315 
       
   316 		// Set the output name
       
   317 		command.add(OUTPUT_FILE.arg());
       
   318 
       
   319 		File file = new File(project.getLocationURI().getPath());
       
   320 		command.add(file.getAbsolutePath() + File.separator
       
   321 				+ projectStore.getOutputFilename());
       
   322 
       
   323 		// Advanced Options
       
   324 		// They are added at the very end of the command line and only if
       
   325 		// defined by the user.
       
   326 		String[] options = projectStore.getAdvancedOptions();
       
   327 
       
   328 		if ((options != null) && (options.length > 0)) {
       
   329 			for (String option : options) {
       
   330 				command.addAll(prepareAdvancedOption(option.trim()));
       
   331 			}
       
   332 		}
       
   333 
       
   334 		return command;
       
   335 	}
       
   336 
       
   337 
       
   338 	private List<String> prepareAdvancedOption(String option) {
       
   339 		List<String> options = new ArrayList<String>();
       
   340 
       
   341 		String optionValue = null;
       
   342 		String argumentValue = null;
       
   343 		
       
   344 		if (option.indexOf(" ") > 0) {
       
   345 			optionValue = option.substring(0, option.indexOf(" "));
       
   346 			argumentValue = option.substring(option.indexOf(" ")).trim();
       
   347 		} else {
       
   348 			optionValue = option;
       
   349 		}
       
   350 		
       
   351 		while (optionValue.startsWith("-")) {
       
   352 			optionValue = optionValue.substring(1);
       
   353 		}
       
   354 
       
   355 		options.add("--" + optionValue);
       
   356 		
       
   357 		if (argumentValue != null && argumentValue.length() != 0) {
       
   358 			options.add(argumentValue);
       
   359 		}
       
   360 		
       
   361 		return options;
       
   362 	}
       
   363 	
       
   364 	private void handleResource(SystemModelGeneratorEnumsForCLI option,
       
   365 			String[] selectedFiles) {
       
   366 		// In the cases below where we have no selected files, we need to define
       
   367 		// a "" string for compatibility with SMG, which does not like an empty array.
       
   368 		switch (option) {
       
   369 		case BORDER_SHAPES_FILES:
       
   370 		case BORDER_STYLES_FILES:
       
   371 		case COLOURS_FILES:
       
   372 		case LOCALISATION_FILES:
       
   373 		case PATTERNS_FILES:
       
   374 		case SHAPES_FILES:
       
   375 		case SYSTEM_INFO_FILES:
       
   376 			if (selectedFiles.length == 0) {
       
   377 				selectedFiles = new String[1];
       
   378 				selectedFiles[0] = "\"\"";
       
   379 			}
       
   380 
       
   381 			break;
       
   382 
       
   383 		case LEVELS_FILES:
       
   384 			if (selectedFiles.length == 0) {
       
   385 				selectedFiles = new String[1];
       
   386 				selectedFiles[0] = "\"\"";
       
   387 			} else {
       
   388 				if (selectedFiles[0].equals("Auto")) {
       
   389 					selectedFiles = new String[] {};
       
   390 				}
       
   391 			}
       
   392 
       
   393 			break;
       
   394 
       
   395 		case DEPENDENCIES_FILES:
       
   396 		case S12_XML_FILES:
       
   397 			if (selectedFiles.length == 0) {
       
   398 				selectedFiles = new String[] {};
       
   399 			}
       
   400 
       
   401 			break;
       
   402 
       
   403 		default:
       
   404 			throw new IllegalArgumentException("Unknown option [" + option
       
   405 					+ "]");
       
   406 
       
   407 		}
       
   408 
       
   409 		for (String file : selectedFiles) {
       
   410 			command.add(option.arg());
       
   411 			command.add((file.equals("\"\"")) ? file : prepareArg(file));
       
   412 		}
       
   413 	}
       
   414 
       
   415 	private String prepareArg(String arg) {
       
   416 		// Escape any XML entities
       
   417 		arg = replace(arg, ampersandPattern.matcher(arg), "&amp;");
       
   418 		arg = replace(arg, lessThanPattern.matcher(arg), "&lt;");
       
   419 		arg = replace(arg, greaterThanPattern.matcher(arg), "&gt;");
       
   420 		arg = replace(arg, singleQuotePattern.matcher(arg), "&apos;");
       
   421 		arg = replace(arg, doubleQuotePattern.matcher(arg), "&quot;");
       
   422 		arg = arg.trim();
       
   423 
       
   424 		// Escape any unicode characters
       
   425 		StringBuffer result = new StringBuffer();
       
   426 
       
   427 		// Get chars as characters may be multibyte
       
   428 		for (char theChar : arg.toCharArray()) {
       
   429 			if ((int) theChar > 127) {
       
   430 				// Turn into XML unicode entity
       
   431 				result.append("&#x" + Integer.toHexString((int) theChar) + ";");
       
   432 			} else {
       
   433 				// Characters < 128 should be the same in all code pages, we
       
   434 				// don't escape these for aesthetic reasons
       
   435 				result.append(theChar);
       
   436 			}
       
   437 		}
       
   438 
       
   439 		return "\"" + result.toString() + "\"";
       
   440 	}
       
   441 
       
   442 	private String replace(String arg, Matcher m, String replacement) {
       
   443 		m.reset();
       
   444 
       
   445 		StringBuffer result = new StringBuffer();
       
   446 
       
   447 		while (m.find()) {
       
   448 			m.appendReplacement(result, replacement);
       
   449 		}
       
   450 
       
   451 		m.appendTail(result);
       
   452 
       
   453 		return result.toString();
       
   454 	}
       
   455 
       
   456 	private void writeToConsoleOutput(final String string) {
       
   457 		// Writes a string to the console output view
       
   458 
       
   459 		Display.getDefault().asyncExec(new Runnable() {
       
   460 			public void run() {
       
   461 				ConsoleOutput.addText(string);
       
   462 			}
       
   463 		});
       
   464 	}
       
   465 }