All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.izforge.izpack.installer.panel.AbstractPanelView Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Julien Ponge, René Krell and the IzPack team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.izforge.izpack.installer.panel;

import com.izforge.izpack.api.adaptator.IXMLElement;
import com.izforge.izpack.api.adaptator.impl.XMLElementImpl;
import com.izforge.izpack.api.data.*;
import com.izforge.izpack.api.exception.IzPackException;
import com.izforge.izpack.api.factory.ObjectFactory;
import com.izforge.izpack.api.handler.AbstractUIHandler;
import com.izforge.izpack.api.installer.DataValidator;
import com.izforge.izpack.api.resource.Messages;
import com.izforge.izpack.api.rules.Condition;
import com.izforge.izpack.data.PanelAction;
import com.izforge.izpack.data.PanelAction.ActionStage;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * Encapsulates a {@link Panel} and its user-interface representation.
 *
 * @author Tim Anderson
 */
public abstract class AbstractPanelView implements PanelView
{

    /**
     * The panel.
     */
    private final Panel panel;

    /**
     * The panel user interface class.
     */
    private final Class viewClass;

    /**
     * The factory for creating the view.
     */
    private final ObjectFactory factory;

    /**
     * The panel index.
     */
    private int index;

    /**
     * The panel user interface.
     */
    private T view;

    /**
     * Determines if the user interface is visible.
     */
    private boolean visible = true;

    /**
     * Ordered list of panel data validators
     */
    private List validators = new ArrayList();

    /**
     * The installation data.
     */
    private final InstallData installData;

    /**
     * Actions to invoke prior to the panel being displayed.
     */
    private final List preActivationActions = new ArrayList();

    /**
     * Actions to invoke prior to the panel being validated.
     */
    private final List preValidationActions = new ArrayList();

    /**
     * Actions to invoke after the panel being validated.
     */
    private final List postValidationActions = new ArrayList();

    /**
     * The logger.
     */
    private static final Logger logger = Logger.getLogger(AbstractPanelView.class.getName());


    /**
     * Constructs a {@code PanelView}.
     *
     * @param panel       the panel
     * @param viewClass   the panel user interface class
     * @param factory     the factory for creating the view
     * @param installData the installation data
     */
    public AbstractPanelView(Panel panel, Class viewClass, ObjectFactory factory, InstallData installData)
    {
        this.panel = panel;
        this.viewClass = viewClass;
        this.factory = factory;
        this.installData = installData;
    }

    /**
     * Returns the panel identifier.
     *
     * @return the panel identifier
     */
    @Override
    public String getPanelId()
    {
        return panel.getPanelId();
    }

    /**
     * Returns the panel.
     *
     * @return the panel
     */
    @Override
    public Panel getPanel()
    {
        return panel;
    }

    /**
     * Returns the panel index.
     * 
* This is the offset of the panel relative to the other panels, visible or not. * * @return the panel index */ @Override public int getIndex() { return index; } /** * Sets the panel index. * * @param index the index */ @Override public void setIndex(int index) { this.index = index; } /** * Returns the panel user interface. *
* The view will be created if it doesn't exist. *
* If the panel has a {@link DataValidator} specified, this will be constructed, with both the panel and view * supplied for injection into it's constructor. * * @return the panel user interface */ @Override public T getView() { if (view == null) { executePreConstructionActions(); view = createView(panel, viewClass); List dataValidatorClassNames = panel.getValidators(); for (String dataValidatorClassName : dataValidatorClassNames) { DataValidator validator = factory.create(dataValidatorClassName, DataValidator.class, panel, view); validators.add(validator); } addActions(panel.getPreActivationActions(), preActivationActions, ActionStage.preactivate); addActions(panel.getPreValidationActions(), preValidationActions, ActionStage.prevalidate); addActions(panel.getPostValidationActions(), postValidationActions, ActionStage.postvalidate); initialise(view, panel, installData); } return view; } /** * Sets the visibility of the panel. * * @param visible if {@code true} the panel is visible, otherwise it is hidden */ @Override public void setVisible(boolean visible) { this.visible = visible; } /** * Determines the visibility of the panel. * * @return {@code true} if the panel is visible, {@code false} if it is hidden */ @Override public boolean isVisible() { return visible; } /** * Determines if the panel is valid. Dynamic variables are automatically refreshed. * * @return {@code true} if the panel is valid */ @Override public boolean isValid() { return isValid(true); } /** * Determines if the panel is valid. * * @param refreshVariables whether to refresh dynamic variables before validating * @return {@code true} if the panel is valid */ @Override public boolean isValid(boolean refreshVariables) { boolean result = false; try { if (refreshVariables) { installData.refreshVariables(); } executePreValidationActions(); List conditions = installData.getDynamicInstallerRequirements(); if (conditions == null || validateDynamicConditions()) { result = validators.size() == 0 || validateData(); } executePostValidationActions(); } catch (IzPackException e) { result = false; } return result; } /** * Save the contents of the panel into install data. */ @Override public void saveData() { //Panel specific should be overwritten my the panel } /** * Determines if the panel can be shown. * * @return {@code true} if the panel can be shown */ @Override public boolean canShow() { boolean visible; String panelId = panel.getPanelId(); try { installData.refreshVariables(); if (panel.hasCondition()) { visible = installData.getRules().isConditionTrue(panel.getCondition()); logger.fine("Panel '" + getPanelId() + "' depending on condition '" + panel.getCondition() + "' " + (visible?"can be shown":"will be skipped")); } else { visible = installData.getRules().canShowPanel(panelId, installData.getVariables()); logger.fine("Panel '" + getPanelId() + "' " + (visible?"can be shown":"will be skipped")); } if (!visible && panel.isDisplayHidden()) { visible = true; logger.fine("Panel '" + getPanelId() + "' depending on displayHidden can be shown read-only"); } if (!visible && panel.hasDisplayHiddenCondition()) { visible = installData.getRules().isConditionTrue(panel.getDisplayHiddenCondition()); panel.setDisplayHidden(visible); logger.fine("Panel '" + getPanelId() + "' depending on displayHiddenCondition '" + panel.getDisplayHiddenCondition() + "' " + (visible?"can be shown read-only":"will be skipped")); } if (visible) { if (!panel.isReadonly() && panel.hasReadonlyCondition()) { boolean readonly = installData.getRules().isConditionTrue(panel.getReadonlyCondition()); panel.setReadonly(readonly); logger.fine("Panel '" + getPanelId() + "' depending on readonlyCondition '" + panel.getReadonlyCondition() + "' " + (readonly?"is forcibly read-only":"is editable")); } } } catch (IzPackException e) { visible = false; } return visible; } /** * Executes actions prior to activating the panel. */ public void executePreActivationActions() { execute(preActivationActions); } /** * Executes actions prior to validating the panel. */ public void executePreValidationActions() { execute(preValidationActions); } /** * Executes actions after validating the panel. */ public void executePostValidationActions() { execute(postValidationActions); } /** * Returns a handler to prompt the user. * * @return the handler */ protected abstract AbstractUIHandler getHandler(); /** * Creates a new view. * * @param panel the panel to create the view for * @param viewClass the view base class * @return the new view */ protected T createView(Panel panel, Class viewClass) { return factory.create(panel.getClassName(), viewClass, panel, this); } /** * Initialises the view. *
* This implementation is a no-op. * * @param view the view to initialise * @param panel the panel the view represents * @param installData the installation data */ protected void initialise(T view, Panel panel, InstallData installData) { } /** * Validates dynamic conditions. * * @return {@code true} if there are no conditions, or conditions validate successfully */ protected boolean validateDynamicConditions() { boolean result = true; try { for (DynamicInstallerRequirementValidator validator : installData.getDynamicInstallerRequirements()) { if (!isValid(validator, installData)) { result = false; break; } } } catch (Throwable exception) { logger.log(Level.WARNING, "Panel " + getPanelId() + ": Could not validate dynamic conditions", exception); result = false; } return result; } /** * Evaluates the panel data validator. * * @return {@code true} if the validator evaluated successfully, or with a warning that the user chose to skip; * otherwise {@code false} */ protected boolean validateData() { boolean result = true; DataValidator[] validatorArray = validators.toArray(new DataValidator[] {}); for (int i = 0; i < validatorArray.length; i++) { DataValidator validator = validatorArray[i]; if (!isValid(validator, i, installData)) { result = false; break; } } return result; } /** * Evaluates a validator. *

* If the validator returns a warning status, then a prompt will be displayed asking the user to skip the * validation or not. * * @param validator the validator to evaluate * @param index the index in the list of validators for finding its appropriate validator condition * @param installData the installation data * @return {@code true} if the validator evaluated successfully, or with a warning that the user chose to skip; * otherwise {@code false} */ private boolean isValid(DataValidator validator, Integer index, InstallData installData) { String dataValidatorConditionId = panel.getValidatorCondition(index); if (dataValidatorConditionId != null) { Condition dataValidatorCondition = installData.getRules().getCondition(dataValidatorConditionId); if (!dataValidatorCondition.isTrue()) { // Skip panel validation logger.fine("Panel " + getPanelId() + ": Skip validation (" + validator.getClass().getName() +")"); return true; } } if (validator instanceof PanelValidator) { logger.finer(validator.getClass().getName() + " is a " + PanelValidator.class.getSimpleName() + " instance"); PanelValidator panelValidator = (PanelValidator) validator; Configurable configurable = getPanel().getValidatorConfiguration(index); if (configurable != null) { final Set names = configurable.getNames(); if (names != null) { for (String name : names) { panelValidator.addConfigurationOption(name, configurable.getConfigurationOption(name)); } } } } else { logger.finer(validator.getClass().getName() + " implements a legacy " + DataValidator.class.getSimpleName() + " interface"); } return isValid(validator, installData); } /** * Evaluates a validator. *

* If the validator returns a warning status, then a prompt will be displayed asking the user to skip the * validation or not. * * @param validator the validator to evaluate * @param installData the installation data * @return {@code true} if the validator evaluated successfully, or with a warning that the user chose to skip; * otherwise {@code false} */ private boolean isValid(DataValidator validator, InstallData installData) { boolean result = false; DataValidator.Status status = validator.validateData(installData); logger.fine("Panel " + getPanelId() + ": Data validation status=" + status + " (" + validator.getClass().getName() + ")"); if (status == DataValidator.Status.OK) { result = true; } else { if (status == DataValidator.Status.WARNING) { String message = getMessage(validator.getWarningMessageId(), true); if (message == null) { logger.warning("Panel " + getPanelId() + ": No warning message for validator " + validator.getClass().getName()); } result = isWarningValid(message, validator.getDefaultAnswer()); } else { String message = getMessage(validator.getErrorMessageId(), true); if (message == null) { logger.warning("Panel " + getPanelId() + ": No error message for validator " + validator.getClass().getName()); message = "Validation error"; } getHandler().emitError(getMessage("data.validation.error.title"), message); } } return result; } /** * Determines the behaviour when a warning is encountered during validation. * * @param message the validation message. May be {@code null} * @param defaultAnswer the default response for warnings * @return {@code true} if the warning doesn't invalidate the panel; {@code false} if it does */ protected boolean isWarningValid(String message, boolean defaultAnswer) { boolean result = false; if (message != null) { if (getHandler().emitWarning(getMessage("data.validation.warning.title"), message)) { result = true; logger.fine("Panel " + getPanelId() + ": User decided to skip validation warning"); } } else { logger.fine("Panel " + getPanelId() + ": No warning message available, using default answer=" + defaultAnswer); result = defaultAnswer; } return result; } /** * Returns the factory. * * @return the factory */ protected ObjectFactory getFactory() { return factory; } /** * Helper to return a localised message, given its id. * * @param id the message identifier * @return the corresponding message or {@code null} if none is found */ protected String getMessage(String id) { return getMessage(id, false); } /** * Executes actions. * * @param actions the actions to execute */ private void execute(List actions) { AbstractUIHandler handler = getHandler(); for (PanelAction action : actions) { action.executeAction(installData, handler); } } /** * Executes actions prior to creating the panel. *
* Both the panel and view are supplied for injection into the action's constructor. */ private void executePreConstructionActions() { List configurations = panel.getPreConstructionActions(); if (configurations != null) { for (PanelActionConfiguration config : configurations) { PanelAction action = factory.create(config.getActionClassName(), PanelAction.class, panel, ActionStage.preconstruct); action.initialize(config); action.executeAction(installData, null); } } } /** * Creates {@link PanelAction}s, adding them to the supplied list. *
* Both the panel and view are supplied for injection into the action's constructor. * * @param configurations the action class names. May be {@code null} * @param actions the actions to add to * @param stage the action stage */ private void addActions(List configurations, List actions, ActionStage stage) { if (configurations != null) { for (PanelActionConfiguration config : configurations) { PanelAction action = factory.create(config.getActionClassName(), PanelAction.class, panel, view, stage); action.initialize(config); actions.add(action); } } } /** * Helper to return a localised message, given its id. * * @param id the message identifier * @param replace if {@code true}, replace any variables in the message with their corresponding values * @return the corresponding message or {@code null} if none is found */ private String getMessage(String id, boolean replace) { String message = null; if (id != null) { Messages messages = installData.getMessages(); message = messages.get(id); if (replace) { message = installData.getVariables().replace(message); } } return message; } /** * Creates an empty root element prepared for adding auto-installation records for this panel. * * @return IXMLElement The prepared panel record XML */ public final IXMLElement createPanelRootRecord() { IXMLElement panelRoot = new XMLElementImpl(panel.getClassName(), installData.getInstallationRecord()); String panelId = panel.getPanelId(); if (panelId != null) { panelRoot.setAttribute(AutomatedInstallData.AUTOINSTALL_PANELROOT_ATTR_ID, panelId); } return panelRoot; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy