UAB Management & Core Refactoring
Ivan Prieto Barreiro10/04/2013
Summary
1. UAB Management2. UAB Core Refactoring (v 1.5.0-beta-01)
– UAB Model– Wizard Components
3. Adding copyright to source files
UAB Management• UAB Core releases
– Major modifications– New functionalities / Minor modifications– Bug fixes
• Requests for improvements/new functionalities/bugs from JIRA
• Regular status meetings for UAB developers– Two meetings per year (starting today)– Notifications about new improvements and functionalities
• Meetings after major releases of UAB Core– Requires modification in the UAB plug-ins to be up to date
• Notification after minor releases of UAB Core– New functionalities, bug fixing, minor improvements, …– Using EN-ICE blogs– Mail notification to UAB developers
Summary
1. UAB Management2. UAB Core Refactoring (v 1.5.0-beta-01)
– UAB Model– Wizard Components
3. Adding copyright to source files
UAB Core Refactoring
AGenerateAction class
• New class that extends the AbstractAction
• Constructors/** * Class constructor. * The icon for the action will be the default generate icon. * @param name Action's name. * @param tooltipText Tooltip text for the action. */public AGenerateAction(String name, String tooltipText);
/** * Class constructor. * @param name Action's name. * @param icon Action's icon. By default the generate icon is included. * @param tooltipText Tooltip text for the action. */public AGenerateAction(String name, Icon icon, String tooltipText);
GenerationException class
• New class to throw generation exceptions
• Constructors/** * Class constructor. * @param message Exception message. */public GenerationException(String message);
/** * Class constructor. * @param message Exception message. * @param hint Hint on how to fix the error. */public GenerationException(String message, String hint);
IPlugin interface modifications
• New interface definition
• Methods removedpublic void initialize();public void plug();public void start(); public void stop();public void unplug();public void shutdown();
• start() method implemented in AGenerationPlugin
APlugin class
• Constructor modifications/** * Class constructor (abstract) */protected APlugin() { // Singleton initialization mySelf = this;}
• No need to initialize the singleton instance in the plug-in implementation
• Implementation of the ILogWriterTemplate interface
AGenerationPlugin class
• Super class of all the generation plug-ins• Major refactoring of generation plugins to this class• Implements ICodeGenerationPlugin
AGenerationPlugin class
• Abstract methods/** * Generate method to be implemented by all the plug-ins. * @throws Exception */protected abstract void generate() throws Exception;
• Constructors (No changes)/** * Class Constructor (abstract). * If the subclass invokes this constructor the plug-in will not be a logic plug-in. */protected AGenerationPlugin();
/** * Class constructor (abstract). * @param isLogicPlugin Boolean value to specify if it is a logic plug-in or not. */protected AGenerationPlugin(boolean isLogicPlugin);
AGenerationPlugin class• Public method to start the plug-in execution/** * Start the plug-in execution. * Decide if launch the application with GUI or without it. */public void start() { // GUI Execution if (CoreManager.getGUIManagement().isGUIRequired()) { // Initialise the General XML Editor initializeGeneralEditor(); runGUI(); } else { runNoGUI(); }}
• Protected methods to start the plug-in execution/** * Initialize the XML General Editor */protected void initializeGeneralEditor();
/** * Run the plug-in generation with graphical interface (FESA XML Editor). */protected void runGUI();
/** * Run the plug-in generation without graphical interface. */protected void runNoGUI();
AGenerationPlugin class• Protected methods to initialize the XML General editor/** * Method executed when a new file is loaded in the General XML Editor. * @return An instance of IUserCallback. */protected IUserCallback getFileLoadedUserAction();
/** * Get the General Editor instance. * @return */protected IGeneralEditor getGeneralEditor();
/** * Add an instance of AGenerateAction in the menu with the specified name. * @param action The instance of AGenerateAction to add. * @param menuName The menu name */protected void addMenuAction(AGenerateAction action, String menuName);
/** * Set the toolbar in the XML General editor. */protected void setEditorToolbar();
/** * Set the menu bar in the XML General editor. */protected void setEditorMenubar();
AGenerationPlugin class• Protected methods to validate and generate/** * Method used to get the instance of AGenerateAction used to validate the specification instances. * @return */protected AGenerateAction getValidateAction();
/** * Used to validate the Excel instances configuration file. */protected void validateInstances() throws Exception;
/** * Method used to get the instance of AGenerateAction used to run the plug-in generation. * @return */protected AGenerateAction getGenerateAction();
/** * Initialization of the generation. The plug-ins must call this method in the generate method. * @param checkCompatibility Flag to specify if the compatibility plug-in/resources must be checked * @throws GenerationException In the following cases: */protected void generate(boolean checkCompatibility) throws Exception;
AGenerationPlugin classprotected AGenerateAction getValidateAction () { ... Thread m_validationThread = new Thread(new Runnable(){ public void run() { try { validateInstances(); // Method implemented in AGenerationPlugin class } catch (GenerationException e) { writeErrorInUABLog(e.getMessage()); String hint = e.getHint(); if (hint!=null) writeConfigInUABLog(hint); } catch (Exception e) { writeErrorWithStackTrace("The validation has failed: " + e.getMessage(), e); } finally { setGenerationPercentage(100); // Resets the UABLogger messages counter UABLogger.resetCounters(); } } }, getId()); m_validationThread.start();}
AGenerationPlugin class/** * Used to validate the Excel instances configuration file. */protected void validateInstances() throws Exception { try { initialize(true); VerificationProcessor verificationProcessor = VerificationProcessor.getInstance(); Boolean readyForGeneration = verificationProcessor.validateDeviceTypeInstances(config, this); if (readyForGeneration){ UABLogger.getLogger("UABLogger").log(Level.INFO, "Ready for generation", type.DATA); } else { UABLogger.getLogger("UABLogger").log(Level.SEVERE,
"Not ready for generation. Check reported problems first.", type.DATA); } } catch (InterruptedException e) { clearInterruptGeneration(); } }
AGenerationPlugin classprotected AGenerateAction getGenerateAction() { ... m_generationThread = new Thread(new Runnable(){ public void run() { try { // Clears the path of the templates processor to prevent loading files from other loaded applications TemplatesProcessor.getInstance().clearPath(); generate(); // The generate() method must be implemented in the sub-classes } catch (GenerationException e) { writeErrorInUABLog(e.getMessage()); String hint = e.getHint(); if (hint!=null) writeConfigInUABLog(hint); } catch (Exception e) { String errorMessage = "The generation has failed"; if (e.getMessage()!=null) errorMessage += e.getMessage(); writeErrorWithStackTrace(errorMessage, e); } finally { // Writes the plug-in exit status in the user report frame logExitStatus(); setGenerationPercentage(100); // Resets the UABLogger messages counter UABLogger.resetCounters(); } } }, getId()); m_generationThread.start();}
AGenerationPlugin class/** * Initialization of the generation. The plug-ins must call this method * in the generate method. * @param checkCompatibility Flag to specify if the compatibility between plug-in and resources must be checked * @throws GenerationException In the following cases: * <ul> * <li>The UnicosApplication.xml file is not loaded</li> * <li>The path to the specs file doesn't exist or it's empty</li> * <li>The specs file couldn't be mapped to a java class</li> * <li>The plug-in is not compatible with the application resources</li> * </ul> */protected void generate(boolean checkCompatibility) throws Exception { // Check if the application XML config file exists ... // Get the specs file location ... // Create the Java representation of the specs file ... // Initialize the log file for the generation ... // Check the compatibility between plug-in and resources (if required) ... // Check if the generation was interrupted by the user ... // Call to the plug-in method to read the configuration parameters reconnectConfiguration(); // Process the semantic rules ... // Check if the generation was interrupted by the user ...}
AGenerationPlugin class
• Semantic rules processing/** * Used to process the semantic check rules and to validate the Excel instances configuration file. */protected void processSemanticCheckRules() throws Exception;
/** * Check if the semantic rules must be executed. * @return TRUE if the semantic rules must be executed, otherwise false. */public boolean executeSemanticRules ();
/** * Method used to know if the execution of the semantic rules is forced due * to a change in the specifications file. * @return TRUE if and only if the semantic rules execution is forced. */public boolean areSemanticRulesForced ();
AGenerationPlugin class
• Access to application data/** * Get the representation of the specifications file. * @return The instance of the specifications file. * @throws Throws a GenerationException if the specs file instance is null. */
public IInstancesFacade getUnicosProject() throws GenerationException;
/** * Get a device type from the specifications source. * @param typeName * @return * @throws GenerationException */public IDeviceType getUnicosDeviceType(String typeName) throws GenerationException;
/** * Get the application XML configuration file (UnicosApplication.xml). * @return The instance of the application configuration file (UnicosApplication.xml). * @throws Throws a GenerationException if the configuration file instance is null. */public XMLConfigMapper getXMLConfig() throws GenerationException;
AGenerationPlugin class
• Access to UnicosApplication.xml data/** * Get the application name from the UnicosApplication. * @return */public String getApplicationName();
/** * Get the application version from the ConfigInfo node of the UnicosApplication. * @return */public String getApplicationVersion();
/** * Get the application UniqueID from the UNICOS Application Configuration * @return String containing the Application Version. */public String getApplicationUniqueID();
/** * Get a config parameter from the UnicosApplication. * @param path The path to the config parameter. * @return */public String getConfigParameter(String path);
AGenerationPlugin class
• Access to UnicosApplication.xml data/** * Get an application parameter from the UnicosApplication. * @param path The path to the application parameter. * @return */public String getApplicationParameter(String path);
/** * Get a plug-in parameter from the UnicosApplication.
* @param path The path to the plug-in parameter. (e.g.: “GeneralData:MainClass”) No pluginId provided! * @return */ public String getPluginParameter(String path);
/** * Get a plug-in parameter map from the UnicosApplication.
* @param path The path to the plug-in parameter. (e.g.: “UNICOSTypesToProcess”) No pluginId provided! * @return */ public Map<String, Object> getPluginParameterMap(String path);
AGenerationPlugin class
• Interrupt plug-in generation/** * Method used to notify the plug-in that the generation has been interrupted by the user. */public void interruptGeneration();
/** * Return TRUE if the generation has been interrupted by the user, otherwise FALSE. * @return */public static boolean isGenerationInterrupted();
/** * Check if the generation was interrupted by the user, in affirmative case * throws a GenerationException. */public void checkGenerationInterrupted() throws GenerationException;
/** * Clear the flag that indicates that the generation has been interrupted * by the user and throw a GenerationException. * @throws GenerationException */protected void clearInterruptGeneration() throws GenerationException;
AGenerationPlugin class
• Buffer processing/** * Used to create a string from a string vector. If the last character of each string in the vector is * different than '\n', appends the new line character at the end of the string. * @param theVector Is the string vector with the generated code. * @param sbuffer A StringBuffer where to append the generated code. * @return The total number of lines found. */protected int processBuffer(Vector<String> theVector, StringBuilder sbuffer);
/** * Used to create a string from a string vector. * @param theVector Is the string vector with the generated code. * @param sbuffer A StringBuffer where to append the generated code. * @param appendLine Flag to specify if the new line character must be added at the end of each * String in the buffer (if it doesn't exist) * @return The total number of lines found. */protected int processBuffer(Vector<String> theVector, StringBuilder sbuffer, boolean appendLine);
AGenerationPlugin class
• Report methods (for UABLog)/** * Write the header of the generation report in the UAB log. */protected void writeGenerationResultsHeader();
[05/04/2013 18:44:28][INFO][PROGRAM] ----------------------------------------------------------------[05/04/2013 18:44:28][INFO][PROGRAM] Generation Report[05/04/2013 18:44:28][INFO][PROGRAM] ----------------------------------------------------------------[05/04/2013 18:44:28][INFO][PROGRAM] Generation performed by iprietob is completed.[05/04/2013 18:44:28][INFO][PROGRAM] The log file has been generated in: C:\...\Bat904\UAB\Log\
/** * Write the number of instances generated in the UAB log. */protected void writeGenerationResultsInstanceNumber();
[05/04/2013 18:44:28][INFO][PROGRAM] Processed devices:[05/04/2013 18:44:28][INFO][PROGRAM] DigitalInput objects: 18[05/04/2013 18:44:28][INFO][PROGRAM] AnalogInput objects: 14[05/04/2013 18:44:28][INFO][PROGRAM] DigitalParameter objects: 2[05/04/2013 18:44:28][INFO][PROGRAM] WordParameter objects: 16[05/04/2013 18:44:28][INFO][PROGRAM] AnalogParameter objects: 97
AGenerationPlugin class
• New methods/** * Get the current date using the format specified in the config. XML file * for the logging (Logging:DateFormat) * @return */public String getDate();
/** * Method used to know if there were errors (SEVERE messages) during the execution. * @return */protected boolean errorsFound();
/** * This function extracts the comments from the comment buffer if not empty and insert it * before the next access to any buffer. * @param theTargetBuffer */protected void insertComment(Vector<String> theTargetBuffer);
/** * Write a comment in the comments buffer. * @param theText */public void writeComment(String theText);
Plug-in modifications• Remove the implementation of the methods:public void initialize();public void plug();public void unplug();public void start();public void stop();public void shutdown();public void initializeGeneralEditor();public void processSemanticCheckRules();public void runGUI();public void runNoGUI();public void insertComment(Vector<String> theTargetBuffer);public void writeComment(String theText);
• Change the visibility of the following methods to protected:protected void generate();protected void reconnectConfiguration();
• Remove the assignment of the singleton instance (mySelf=this)• Remove the implementation of GenerateAction
– All parameters must be read in the reconnectConfiguration() method.– All generation logic must be implemented in the generate() method.
Summary
1. UAB Management2. UAB Core Refactoring (v 1.5.0-beta-01)
– UAB Model– Wizard Components
3. Adding copyright to source files
New hierarchy of classes
New Classes
* Relationships between classes are hidden
ActionMap classes• No changes in WizardActionMap• Define the typical wizard actions
– Back action– Next action– Exit action
• An action defines:– Action text– Icon– Key– Description– Mnemonic
• GenerateActionMap defines a new action for generation• Each Wizard must define its own action map with specific actions
– Instance Generation– Logic Generation– …
Panel Descriptors• New class and interface:
– IGenerationPanelDescriptor– GenerationPanelDescriptor
• Methods should be overwrittenby subclasses when necessary
New Classes
AWizard class• The Wizard class must inherit from AGenerationWizard instead of AWizardpublic abstract class AWizard extends APlugin implements IWizard {
/** Static reference to the wizard instance **/ protected static AWizard wizardInstance = null;
/** * Class constructor. */ public AWizard () { wizardInstance = this; }
/** * Provides access to this code generation plug-in through the IManager Interface . * @return research.ch.cern.unicos.plugins.interfaces.IPlugin */ public static IWizard getWizardManager() { return (IWizard) wizardInstance; }};
AGenerationWizard class• The Wizard plug-ins must inherit from AGenerationWizard instead of AWizard• Abstract methods/** * Get the instance of the wizard controller. * @return */protected abstract IGenerationController getWizardController();
/** * Get the identifier of the initial panel. * @return */public abstract Object getInitialPanelIdentifier();
• Implemented methods/** * Wizard initialization: compose UnicosApplication.xml, load java beans, render wizard panels… */protected void initialize() throws Exception;
/** * Start the wizard execution: initialization, set initial panel, process call parameters, * show wizard frame. */public void start();
AGenerationWizard class• Implemented methods/** * Process the VM parameters received. The actions implemented are: * - Create a new application * - Open an existing application * - Upgrade an existing application */protected void processParameters();
/** * Trigger the creation of a new application. * @param applicationPath The path for the new application */protected void createNewApplication(String applicationPath);
/** * Trigger the opening of an application. * @param applicationPath The application path. */protected void openApplication(String applicationPath);
/** * Trigger the upgrade of an application. * @param applicationPath The application path. */protected void upgradeApplication(String applicationPath);
/** * Get the set of plug-ins available in the wizard. * @return */public Set<String> getPluginsSet();
Wizard modifications• Modify the super class to AGenerationWizard• Remove the variables:private boolean panelsLoaded;private Resource technicalConfigResource;private Resource wizardConfigResource;private Resource unicosApplicationResource;public final static String actionKey = "action";public final static String appLocationKey = "config";public final static String platformKey = "platform";public final static String resourcesKey = "resourcesVersion";public final static String newApplication = "NEW_APPLICATION";public final static String openApplication = "OPEN_APPLICATION";public final static String upgradeApplication = "UPGRADE_APPLICATION";
• Modify the type of the fieldsprivate IWizardModel model; --> private IGenerationModel model;private IWizardController controller; --> private IGenerationController controller;
• Remove the implementation of the methods:public void initialize();public void plug();public void unplug();public void stop();public void shutdown();public void initialize();public void start();private void processParameters();public Resource getUnicosApplicationResource();public void createNewApplication(), openApplication(), upgradeApplication(), showErrorDialog().
• Remove the assignment of the singleton instance (wizardInstance=this)
Wizard implementationpublic class Wizard extends AGenerationWizard implements IWizard {
public Wizard() { try { // Instantiate the Model-View-Controller classes model = new CpcModel(super.getPluginsSet()); controller = new CpcWizardController(); wizardGUI = new CpcGui(model, controller, 650, 730); wizardGUI.getFrame().setTitle("UAB CPC-Wizard v" + versionId); } catch (Exception e) { ... }}
public static IPlugin getPluginManager() { if (wizardInstance == null) { wizardInstance = new Wizard(); } return (IPlugin) wizardInstance; }
public String getId() { return pluginId; }public String getDescription() { return pluginDescription; }public String getVersionId() { return versionId; }public IWizardGUI getWizardGUI() { return wizardGUI; }public IGenerationModel getWizardModel() { return model; }protected IGenerationController getWizardController() { return controller; }public Object getInitialPanelIdentifier() { return IntroductionPanelDescriptor.IDENTIFIER; }
}
AModel class• Handle panels• Set property values:
– BackButton (Text, Action, Icon, Enabled)– NextButton (Text, Action, Icon, Enabled)– CancelButton (Text, Action, Icon, Enabled)
• Property change listener for:– Current panel descriptor– BackButton (Text, Action, Icon, Enabled)– NextButton (Text, Action, Icon, Enabled)– CancelButton (Text, Action, Icon, Enabled)
GenerationModel class• Model for application specific data:
– Wizard mode (Create, open, upgrade)– Project name– Application (name, version, path)– Specs path– Resources version– Upgrade dialog– Navigation buttons (Text, Action, Icon, Enabled, Visible)
• Property change listener for:– Navigation buttons– Upgrade dialog
Specific Model implementation• Generally not necessary to implement specific models (Use GenerationModel)• But in some cases it can be necessary: e.g. CpcModelpublic class CpcModel extends GenerationModel { /** * Set the application type (Siemens, Schneider, ...) * @param type */ public void setApplicationType (CpcApplicationType type);
/** * Get the application type * @return */ public CpcApplicationType getApplicationType ();
/** * Load the data in the panels (only the application type panels are loaded) */ @Override public void loadPanelData();}
AWizardController class• Abstract methods/** * Method called when the Next button has been pressed. */protected abstract void nextButtonPressed() throws Exception;
/** * Reset the buttons to support the original panel rules, * including whether the next or back buttons are enabled or * disabled, or if the panel is finishable. */public abstract void resetButtonsToPanelRules();
• Implementation of basic GUI actions (ActionListener)
GenerationController class• Basic controller implementation/** * Implementation of typical actions: New app., open app., upgrade app, * call to generate(), set next panel. */protected void nextButtonPressed();
/** * Execute a plug-in generation. Called from nextButtonPressed(). */protected void generate();
/** * Method used to know if the semantic check rules must be executed. * Called from generate(..) method * @param pluginId The plug-in identifier. * @return TRUE if the semantic rules must be executed, otherwise FALSE. */protected boolean executeSemanticRules (String pluginId);
public void triggerNewApplication(String projectPath, String resources) throws Exception;
public void triggerLoadApplication(String projectPath) throws Exception;public void triggerUpgradeApplication(String projectPath) throws Exception;
Specific Controller implementationpublic class CietWizardController extends GenerationController { public CietWizardController() throws Exception { super(); super.createApplicationMessage = "Creating a new CIET application"; // This is necessary to create the singleton instance of the CietActionMap CietActionMap.getInstance(); }
@Override protected void nextButtonPressed() throws Exception { IGenerationModel model = getModel(); IPanelDescriptor descriptor = model.getCurrentPanelDescriptor(); if (descriptor.getPanelDescriptorIdentifier().equals(AppConfigDescriptor.IDENTIFIER)){ // Do specific actions for the current wizard. } super.nextButtonPressed(); }
/** Method called after the creation of a new application and after an application upgrade. **/ @Override protected void cleanupApplication() { // Remove the PLC declarations XMLConfigMapper config = CoreManager.getITechnicalParameters().getXMLConfigMapper(); config.removeNodes("//applicationData/PLCDeclarations"); config.saveXML(); }}
AWizardGUI class• New constructors to provide a frame icon/** * Class constructor. * @param model The instance of the IWizardModel. * @param controller The instance of the IWizardController. * @param icon The wizard icon. */public AWizardGUI (IWizardModel model, IWizardController controller, Icon icon);
/** * Class constructor. * @param model The instance of the IWizardModel. * @param controller The instance of the IWizardController. * @param width The minimum and preferred width. * @param height The minimum and preferred height. * @param icon The wizard icon. */public AWizardGUI (IWizardModel model, IWizardController controller, int width, int height, Icon icon);
GenerationGUI class• Constructors to provide a frame icon/** * Class constructor. * @param model The instance of the IWizardModel. * @param controller The instance of the IWizardController. * @param image The wizard image. */public GenerationGUI (IWizardModel model, IWizardController controller, ImageIcon image);
/** * Class constructor. * @param model The instance of the IWizardModel. * @param controller The instance of the IWizardController. * @param width The minimum and preferred width. * @param height The minimum and preferred height. * @param image The wizard image. */public GenerationGUI (IWizardModel model, IWizardController controller, int width, int height, ImageIcon image);
Specific GUI implementationpublic class CietGui extends GenerationGUI { public static String CIET_FEC_INSTANCES_GENERATOR_TEXT = "Fesa Generator"; public static String CIET_WINCCOA_CONFIG_GENERATOR_TEXT = "WinCC OA Generator";
/** Class constructor. */ public CietGui(IGenerationModel model, IGenerationController controller, int width, int height) { super(model, controller, width, height); } static { try { // Wizard icon initialization WIZARD_ICON = new ImageIcon(
new ClassPathResource("/research/ch/cern/unicos/plugins/wizard/icons/ciet.png").getURL()); } catch (Exception mre) { System.out.println(mre); } }}
Summary
1. UAB Management2. UAB Core Refactoring (v 1.5.0-beta-01)
– UAB Model– Wizard Components
3. Adding copyright to source files
UAB-655 : Add Copyright information
• Add the copyright information on the top of the source filesmvn license:format
/** * UNICOS * * Copyright (C) CERN 2013 All rights reserved */
• Verify if some files miss the license headermvn license:check
• Remove existing license headermvn license:remove