modules/core/domain/src/main/java/org/rhq/core/domain/sync/ImportReport.java | 44 + modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/MetricTemplateSynchronizer.java | 17 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerBean.java | 173 ++++-- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerLocal.java | 16 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerRemote.java | 9 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizedEntity.java | 10 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizerFactory.java | 42 + modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SystemSettingsSynchronizer.java | 3 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/Importer.java | 15 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/MetricTemplateImporter.java | 56 ++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/SystemSettingsImporter.java | 14 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/ConsistencyValidator.java | 36 - modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/DeployedAgentPluginsValidator.java | 14 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/EntityValidator.java | 52 ++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MaxCountValidator.java | 52 ++ modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MetricTemplateValidator.java | 121 ---- modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/SystemSettingsValidator.java | 48 - modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/UniquenessValidator.java | 50 + modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java | 5 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/DeployedAgentPluginsValidatorTest.java | 3 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/ExportingInputStreamTest.java | 9 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MaxCountValidatorTest.java | 52 ++ modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateExporterTest.java | 17 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateImporterTest.java | 42 + modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateValidatorTest.java | 161 ------ modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java | 253 ++++++++-- modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsImporterTest.java | 1 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsValidatorTest.java | 22 modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/UniquenessValidatorTest.java | 51 ++ 29 files changed, 855 insertions(+), 533 deletions(-)
New commits: commit f3f7a0535ce7f62bd1c0ddd85bd1d24a835fc446 Author: Lukas Krejci lkrejci@redhat.com Date: Mon Nov 7 12:06:01 2011 +0100
[BZ 749126] - Loosening validation requirements on import. This commit is quite big due to the refactoring but does only a couple of simple things:
1) The SynchronizationManagerRemote.importAllSubsystems now returns an ImportReport which contains the notes from subsystem importers about "interesting" events during the import. This is used to report warnings or other info to the caller of the import. Namely the MetricTemplateImporter now reports all the metric templates from the export file that were not present in the target database (which basically means that source and target RHQ install had different plugins installed).
2) Import is lenient about unknown validator classes (this is to not choke on "old" import files that still may be perfectly valid).
3) The former ConsistencyValidator has been split into 2 separate concepts: ConsistencyValidator - persists its config into the export file, checks the consistency of the target RHQ install as a whole. EntityValidator - configured by the importer, does NOT persist anything into the export file, used to validate individual entities in the export file before the import begins.
4) Some new unit tests and a couple of simple changes in the code to support better testability.
5) DeployedAgentPluginsValidator was "decommissioned" but left in the codebase as an example implementation.
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/sync/ImportReport.java b/modules/core/domain/src/main/java/org/rhq/core/domain/sync/ImportReport.java new file mode 100644 index 0000000..d9baab7 --- /dev/null +++ b/modules/core/domain/src/main/java/org/rhq/core/domain/sync/ImportReport.java @@ -0,0 +1,44 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.core.domain.sync; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * + * + * @author Lukas Krejci + */ +public class ImportReport implements Serializable { + + private static final long serialVersionUID = 1L; + + private Map<String, String> importerNotes; + + public Map<String, String> getImporterNotes() { + if (importerNotes == null) { + importerNotes = new HashMap<String, String>(); + } + + return importerNotes; + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/MetricTemplateSynchronizer.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/MetricTemplateSynchronizer.java index 913c981..1dcdd9c 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/MetricTemplateSynchronizer.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/MetricTemplateSynchronizer.java @@ -19,6 +19,7 @@
package org.rhq.enterprise.server.sync;
+import java.util.Collections; import java.util.HashSet; import java.util.Set;
@@ -36,7 +37,7 @@ import org.rhq.enterprise.server.sync.importers.Importer; import org.rhq.enterprise.server.sync.importers.MetricTemplateImporter; import org.rhq.enterprise.server.sync.validators.ConsistencyValidator; import org.rhq.enterprise.server.sync.validators.DeployedAgentPluginsValidator; -import org.rhq.enterprise.server.sync.validators.MetricTemplateValidator; +import org.rhq.enterprise.server.sync.validators.UniquenessValidator; import org.rhq.enterprise.server.util.LookupUtil;
/** @@ -50,17 +51,15 @@ public class MetricTemplateSynchronizer implements Synchronizer<MeasurementDefin private EntityManager entityManager; private MeasurementDefinitionManagerLocal measurementDefinitionManager; private MeasurementScheduleManagerLocal measurementScheduleManager; - private PluginManagerLocal pluginManager;
public MetricTemplateSynchronizer() { - this(LookupUtil.getMeasurementDefinitionManager(), LookupUtil.getMeasurementScheduleManager(), LookupUtil.getPluginManager()); + this(LookupUtil.getMeasurementDefinitionManager(), LookupUtil.getMeasurementScheduleManager()); }
public MetricTemplateSynchronizer(MeasurementDefinitionManagerLocal measurementDefinitionManager, - MeasurementScheduleManagerLocal measurementScheduleManager, PluginManagerLocal pluginManager) { + MeasurementScheduleManagerLocal measurementScheduleManager) { this.measurementDefinitionManager = measurementDefinitionManager; this.measurementScheduleManager = measurementScheduleManager; - this.pluginManager = pluginManager; }
@Override @@ -69,19 +68,19 @@ public class MetricTemplateSynchronizer implements Synchronizer<MeasurementDefin this.entityManager = entityManager; }
+ @Override public Exporter<MeasurementDefinition, MetricTemplate> getExporter() { return new MetricTemplateExporter(subject, measurementDefinitionManager); }
+ @Override public Importer<MeasurementDefinition, MetricTemplate> getImporter() { return new MetricTemplateImporter(subject, entityManager, measurementScheduleManager); }
+ @Override public Set<ConsistencyValidator> getRequiredValidators() { - HashSet<ConsistencyValidator> ret = new HashSet<ConsistencyValidator>(); - ret.add(new DeployedAgentPluginsValidator(pluginManager)); - ret.add(new MetricTemplateValidator()); - return ret; + return Collections.emptySet(); }
} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerBean.java index af848b1..992687e 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerBean.java @@ -30,6 +30,7 @@ import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -54,7 +55,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.auth.Subject; -import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.sync.ConsistencyValidatorFailureReport; import org.rhq.core.domain.sync.ExportReport; @@ -62,12 +62,13 @@ import org.rhq.core.domain.sync.ExportWrapper; import org.rhq.core.domain.sync.ExporterMessages; import org.rhq.core.domain.sync.ImportConfiguration; import org.rhq.core.domain.sync.ImportConfigurationDefinition; +import org.rhq.core.domain.sync.ImportReport; import org.rhq.core.util.stream.StreamUtil; import org.rhq.enterprise.server.RHQConstants; -import org.rhq.enterprise.server.authz.RequiredPermission; import org.rhq.enterprise.server.sync.importers.ExportedEntityMatcher; import org.rhq.enterprise.server.sync.importers.Importer; import org.rhq.enterprise.server.sync.validators.ConsistencyValidator; +import org.rhq.enterprise.server.sync.validators.EntityValidator; import org.rhq.enterprise.server.sync.validators.InconsistentStateException; import org.rhq.enterprise.server.xmlschema.ConfigurationInstanceDescriptorUtil;
@@ -85,18 +86,25 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, private EntityManager entityManager;
private JAXBContext defaultImportConfigurationJAXBContext; + + private SynchronizerFactory synchronizerFactory = new SynchronizerFactory();
public SynchronizationManagerBean() { try { - defaultImportConfigurationJAXBContext = JAXBContext.newInstance(DefaultImportConfigurationDescriptor.class); + defaultImportConfigurationJAXBContext = JAXBContext.newInstance(DefaultImportConfigurationDescriptor.class); } catch (JAXBException e) { throw new IllegalStateException("Failed to create DefaultImportConfigurationDescriptor unmarshaller. This should never happen."); } }
+ //for test purposes + @Override + public void setSynchronizerFactory(SynchronizerFactory factory) { + this.synchronizerFactory = factory; + } + @Override @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) - @RequiredPermission(Permission.MANAGE_INVENTORY) public ExportReport exportAllSubsystems(Subject subject) { ExportWrapper localExport = exportAllSubsystemsLocally(subject);
@@ -131,17 +139,10 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal,
@Override @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) - @RequiredPermission(Permission.MANAGE_INVENTORY) public ExportWrapper exportAllSubsystemsLocally(Subject subject) { - Set<Synchronizer<?, ?>> allSynchronizers = new HashSet<Synchronizer<?, ?>>(); + Set<Synchronizer<?, ?>> allSynchronizers = getInitializedSynchronizers(subject); Map<String, ExporterMessages> messages = new HashMap<String, ExporterMessages>();
- for (SynchronizedEntity e : SynchronizedEntity.values()) { - Synchronizer<?, ?> synchronizer = e.getSynchronizer(); - synchronizer.initialize(subject, entityManager); - allSynchronizers.add(synchronizer); - } - try { return new ExportWrapper(messages, new ExportingInputStream(allSynchronizers, messages)); } catch (IOException e) { @@ -150,8 +151,7 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, }
@Override - @RequiredPermission(Permission.MANAGE_INVENTORY) - public void importAllSubsystems(Subject subject, InputStream exportFile, List<ImportConfiguration> configurations) + public ImportReport importAllSubsystems(Subject subject, InputStream exportFile, List<ImportConfiguration> configurations) throws ValidationException, ImportException {
File tmpFile = null; @@ -170,13 +170,15 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, }
InputStream in = null; - try { + try { + Map<String, Configuration> configsPerImports = getConfigPerImporter(configurations); + in = new GZIPInputStream(new BufferedInputStream(new FileInputStream(tmpFile))); - validateExport(subject, in); + validateExport(subject, in, configsPerImports); in.close();
in = new GZIPInputStream(new BufferedInputStream(new FileInputStream(tmpFile))); - importExportFile(subject, in, getConfigPerImporter(configurations)); + return importExportFile(subject, in, configsPerImports); } catch (XMLStreamException e) { throw new ImportException("Failed import due to XML parsing error.", e); } catch (IOException e) { @@ -188,24 +190,21 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, }
@Override - @RequiredPermission(Permission.MANAGE_INVENTORY) - public void importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> configurations) + public ImportReport importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> configurations) throws ValidationException, ImportException { - importAllSubsystems(subject, new ByteArrayInputStream(exportFile), configurations); + return importAllSubsystems(subject, new ByteArrayInputStream(exportFile), configurations); }
@Override - @RequiredPermission(Permission.MANAGE_INVENTORY) public void validate(Subject subject, InputStream exportFile) throws ValidationException { try { - validateExport(subject, exportFile); + validateExport(subject, exportFile, Collections.<String, Configuration>emptyMap()); } catch (XMLStreamException e) { throw new ValidationException("Failed to parse the export file.", e); } }
@Override - @RequiredPermission(Permission.MANAGE_INVENTORY) public void validate(Subject subject, byte[] exportFile) throws ValidationException { validate(subject, new ByteArrayInputStream(exportFile)); } @@ -235,8 +234,7 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, public List<ImportConfigurationDefinition> getImportConfigurationDefinitionOfAllSynchronizers() { List<ImportConfigurationDefinition> ret = new ArrayList<ImportConfigurationDefinition>();
- for (SynchronizedEntity e : SynchronizedEntity.values()) { - Synchronizer<?, ?> syn = e.getSynchronizer(); + for (Synchronizer<?, ?> syn : synchronizerFactory.getAllSynchronizers()) { ret.add(new ImportConfigurationDefinition(syn.getClass().getName(), syn.getImporter() .getImportConfigurationDefinition())); } @@ -244,12 +242,12 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, return ret; }
- private void validateExport(Subject subject, InputStream exportFile) throws ValidationException, XMLStreamException { + private void validateExport(Subject subject, InputStream exportFile, Map<String, Configuration> importConfigs) throws ValidationException, XMLStreamException { XMLStreamReader rdr = XMLInputFactory.newInstance().createXMLStreamReader(exportFile);
try { Set<ConsistencyValidatorFailureReport> failures = new HashSet<ConsistencyValidatorFailureReport>(); - Set<ConsistencyValidator> executedValidators = new HashSet<ConsistencyValidator>(); + Set<ConsistencyValidator> consistencyValidators = new HashSet<ConsistencyValidator>();
while (rdr.hasNext()) { switch (rdr.next()) { @@ -258,6 +256,11 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, if (SynchronizationConstants.VALIDATOR_ELEMENT.equals(tagName)) { ConsistencyValidator validator = null; String validatorClass = rdr.getAttributeValue(null, SynchronizationConstants.CLASS_ATTRIBUTE); + if (!isConsistencyValidatorClass(validatorClass)) { + LOG.info("The export file contains an unknown consistency validator: " + validatorClass + ". Ignoring."); + continue; + } + try { validator = validateSingle(rdr, subject); } catch (Exception e) { @@ -265,14 +268,12 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, printExceptionToString(e))); } if (validator != null) { - executedValidators.add(validator); + consistencyValidators.add(validator); } } else if (SynchronizationConstants.ENTITIES_EXPORT_ELEMENT.equals(tagName)) { - //all the validators preceed the importers in the export file so we can now check if the - //validator was already run String synchronizerClass = rdr.getAttributeValue(null, SynchronizationConstants.ID_ATTRIBUTE); try { - failures.addAll(validateEntities(rdr, subject, executedValidators)); + failures.addAll(validateEntities(rdr, subject, consistencyValidators, importConfigs)); } catch (Exception e) { throw new ValidationException( "Validation failed unexpectedly while processing the entities exported by the synchronizer '" @@ -290,24 +291,38 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, } }
- private Set<ConsistencyValidatorFailureReport> validateEntities(XMLStreamReader rdr, Subject subject, - Set<ConsistencyValidator> executedValidators) throws Exception { + /** + * @param validatorClass + * @return + */ + private boolean isConsistencyValidatorClass(String validatorClass) { + try { + Class<?> cls = Class.forName(validatorClass); + + return ConsistencyValidator.class.isAssignableFrom(cls); + } catch (Exception e) { + return false; + } + } + + private <E, X> Set<ConsistencyValidatorFailureReport> validateEntities(XMLStreamReader rdr, Subject subject, + Set<ConsistencyValidator> consistencyValidators, Map<String, Configuration> importConfigurations) throws Exception { String synchronizerClass = rdr.getAttributeValue(null, SynchronizationConstants.ID_ATTRIBUTE); HashSet<ConsistencyValidatorFailureReport> ret = new HashSet<ConsistencyValidatorFailureReport>();
- Synchronizer<?, ?> synchronizer = instantiate(synchronizerClass, Synchronizer.class, + @SuppressWarnings("unchecked") + Synchronizer<E, X> synchronizer = instantiate(synchronizerClass, Synchronizer.class, "The id attribute of entities doesn't correspond to a class implementing the Synchronizer interface.");
synchronizer.initialize(subject, entityManager);
- Importer<?, ?> importer = synchronizer.getImporter(); + Importer<E, X> importer = synchronizer.getImporter();
- //pre-init the validators so that we can reuse them in the loop below - Set<ConsistencyValidator> validators = synchronizer.getRequiredValidators(); - for(ConsistencyValidator v : validators) { - v.initialize(subject, entityManager); - - if (!executedValidators.contains(v)) { + Set<ConsistencyValidator> requriedConsistencyValidators = synchronizer.getRequiredValidators(); + + //check that all the required consistency validators were run + for(ConsistencyValidator v : requriedConsistencyValidators) { + if (!consistencyValidators.contains(v)) { ret.add(new ConsistencyValidatorFailureReport(v.getClass().getName(), "The validator '" + v.getClass().getName() + "' is required by the synchronizer '" + synchronizerClass + "' but was not found in the export file.")); @@ -319,29 +334,48 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, return ret; }
+ boolean configured = false; + Configuration importConfiguration = importConfigurations.get(synchronizerClass); + + Set<EntityValidator<X>> validators = null; + + //the passed in configuration has precedence over the default one inlined in + //the config file. + if (importConfiguration != null) { + importer.configure(importConfiguration); + validators = importer.getEntityValidators(); + for(EntityValidator<X> v : validators) { + v.initialize(subject, entityManager); + } + configured = true; + } + while (rdr.hasNext()) { boolean bailout = false; switch (rdr.next()) { case XMLStreamConstants.START_ELEMENT: - if (SynchronizationConstants.DATA_ELEMENT.equals(rdr.getName().getLocalPart())) { - rdr.nextTag(); - Object exportedEntity = importer.unmarshallExportedEntity(new ExportReader(rdr)); - Class<?> exportedEntityClass = exportedEntity.getClass(); + if (SynchronizationConstants.DEFAULT_CONFIGURATION_ELEMENT.equals(rdr.getName().getLocalPart())) { + if (!configured) { + importConfiguration = getDefaultConfiguration(rdr); + } + } else if (SynchronizationConstants.DATA_ELEMENT.equals(rdr.getName().getLocalPart())) {
- for (ConsistencyValidator validator : validators) { - boolean shouldCheck = false; - for (Class<?> cls : validator.getValidatedEntityTypes()) { - if (cls.isAssignableFrom(exportedEntityClass)) { - shouldCheck = true; - break; - } - } - - if (!shouldCheck) { - //ok, this validator doesn't want to validate this type of entity - continue; + //first check if the configure method has been called + if (!configured) { + importer.configure(importConfiguration); + validators = importer.getEntityValidators(); + for(EntityValidator<X> v : validators) { + v.initialize(subject, entityManager); } + configured = true; + } + + //now do the validation
+ rdr.nextTag(); + X exportedEntity = importer.unmarshallExportedEntity(new ExportReader(rdr)); + + for (EntityValidator<X> validator : validators) { try { validator.validateExportedEntity(exportedEntity); } catch (Exception e) { @@ -367,17 +401,23 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, return ret; }
- private void importExportFile(Subject subject, InputStream exportFile, + private ImportReport importExportFile(Subject subject, InputStream exportFile, Map<String, Configuration> importerConfigs) throws ImportException, XMLStreamException { XMLStreamReader rdr = XMLInputFactory.newInstance().createXMLStreamReader(exportFile);
+ ImportReport report = new ImportReport(); + while (rdr.hasNext()) { switch (rdr.next()) { case XMLStreamReader.START_ELEMENT: String tagName = rdr.getName().getLocalPart(); if (SynchronizationConstants.ENTITIES_EXPORT_ELEMENT.equals(tagName)) { try { - importSingle(subject, importerConfigs, rdr); + String synchronizer = rdr.getAttributeValue(null, SynchronizationConstants.ID_ATTRIBUTE); + String notes = importSingle(subject, importerConfigs, rdr); + if (notes != null) { + report.getImporterNotes().put(synchronizer, notes); + } } catch (Exception e) { //fail fast on the import errors... This runs in a single transaction //so all imports done so far will get rolled-back. @@ -390,6 +430,8 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, break; } } + + return report; }
private ConsistencyValidator validateSingle(XMLStreamReader rdr, Subject subject) throws InstantiationException, @@ -410,7 +452,7 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, return validator; }
- private <E, X> void importSingle(Subject subject, Map<String, Configuration> importConfigs, XMLStreamReader rdr) + private <E, X> String importSingle(Subject subject, Map<String, Configuration> importConfigs, XMLStreamReader rdr) throws Exception { String synchronizerClassName = rdr.getAttributeValue(null, SynchronizationConstants.ID_ATTRIBUTE);
@@ -477,7 +519,7 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, importer.configure(importConfiguration); }
- importer.finishImport(); + return importer.finishImport(); }
private static String printExceptionToString(Throwable t) { @@ -499,6 +541,15 @@ public class SynchronizationManagerBean implements SynchronizationManagerLocal, return desiredClass.cast(instance); }
+ private Set<Synchronizer<?, ?>> getInitializedSynchronizers(Subject subject) { + Set<Synchronizer<?, ?>> ret = synchronizerFactory.getAllSynchronizers(); + for(Synchronizer<?, ?> s : ret) { + s.initialize(subject, entityManager); + } + + return ret; + } + private Map<String, Configuration> getConfigPerImporter(List<ImportConfiguration> list) { Map<String, Configuration> ret = new HashMap<String, Configuration>();
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerLocal.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerLocal.java index e391f25..fd4d425 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerLocal.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerLocal.java @@ -31,6 +31,7 @@ import org.rhq.core.domain.sync.ExportReport; import org.rhq.core.domain.sync.ExportWrapper; import org.rhq.core.domain.sync.ImportConfiguration; import org.rhq.core.domain.sync.ImportConfigurationDefinition; +import org.rhq.core.domain.sync.ImportReport;
/** * @@ -60,7 +61,18 @@ public interface SynchronizationManagerLocal {
void validate(Subject subject, InputStream exportFile) throws ValidationException;
- void importAllSubsystems(Subject subject, InputStream exportFile, List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException; + ImportReport importAllSubsystems(Subject subject, InputStream exportFile, List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException; + + /** + * <b>Provided for testability reasons. DON'T USE OUTSIDE TESTS.</b> + * <p> + * Using this method one can provide a custom factory + * for {@link Synchronizer}s. This way one can export/import different types of entities + * than by default. + * + * @param factory + */ + void setSynchronizerFactory(SynchronizerFactory factory);
//-------- THE FOLLOWING METHODS ARE SHARED WITH THE REMOTE INTERFACE ------------
@@ -93,5 +105,5 @@ public interface SynchronizationManagerLocal { /** * @see SynchronizationManagerRemote#importAllSubsystems(Subject, byte[], Set) */ - void importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException; + ImportReport importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException; } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerRemote.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerRemote.java index 0cefd8c..eb6b5c9 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerRemote.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizationManagerRemote.java @@ -28,6 +28,7 @@ import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.sync.ExportReport; import org.rhq.core.domain.sync.ImportConfiguration; import org.rhq.core.domain.sync.ImportConfigurationDefinition; +import org.rhq.core.domain.sync.ImportReport;
/** * @@ -75,9 +76,11 @@ public interface SynchronizationManagerRemote { * * @param subject the authenticated user * @param exportFile the contents of the export file - * @param importerConfigurations the configurations of individual importers to be used when importing + * @param importerConfigurations the configurations of individual importers to be used when importing or null + * if the default configurations should be used for all the importers. * - * @return the report describing the result of the export + * @return the report describing the result of the import */ - void importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException; + ImportReport importAllSubsystems(Subject subject, byte[] exportFile, + List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException; } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizedEntity.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizedEntity.java index 21e15b0..6668947 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizedEntity.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizedEntity.java @@ -19,16 +19,12 @@
package org.rhq.enterprise.server.sync;
-import org.rhq.enterprise.server.sync.exporters.Exporter; -import org.rhq.enterprise.server.sync.exporters.MetricTemplateExporter; -import org.rhq.enterprise.server.sync.exporters.SystemSettingsExporter; -import org.rhq.enterprise.server.sync.importers.Importer; -import org.rhq.enterprise.server.sync.importers.MetricTemplateImporter; -import org.rhq.enterprise.server.sync.importers.SystemSettingsImporter;
/** * The enum of all possible synchronized entities. - * + * This is used in the {@link SynchronizerFactory#getAllSynchronizers()} to provide + * the synchronizers to the rest of the config sync machinery. + * * @author Lukas Krejci */ public enum SynchronizedEntity { diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizerFactory.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizerFactory.java new file mode 100644 index 0000000..2ffada1 --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SynchronizerFactory.java @@ -0,0 +1,42 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.server.sync; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * A factory for obtaining synchronizers. + * This is mainly useful for test purposes where this class can be subclassed + * and passed to the {@link SynchronizationManagerBean}. + * + * @author Lukas Krejci + */ +public class SynchronizerFactory { + + public Set<Synchronizer<?, ?>> getAllSynchronizers() { + LinkedHashSet<Synchronizer<?, ?>> ret = new LinkedHashSet<Synchronizer<?,?>>(); + for (SynchronizedEntity e : SynchronizedEntity.values()) { + ret.add(e.getSynchronizer()); + } + + return ret; + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SystemSettingsSynchronizer.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SystemSettingsSynchronizer.java index da0b0e7..dc62060 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SystemSettingsSynchronizer.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/SystemSettingsSynchronizer.java @@ -31,7 +31,6 @@ import org.rhq.enterprise.server.sync.exporters.SystemSettingsExporter; import org.rhq.enterprise.server.sync.importers.Importer; import org.rhq.enterprise.server.sync.importers.SystemSettingsImporter; import org.rhq.enterprise.server.sync.validators.ConsistencyValidator; -import org.rhq.enterprise.server.sync.validators.SystemSettingsValidator; import org.rhq.enterprise.server.system.SystemManagerLocal; import org.rhq.enterprise.server.util.LookupUtil;
@@ -67,7 +66,7 @@ public class SystemSettingsSynchronizer implements Synchronizer<NoSingleEntity, }
public Set<ConsistencyValidator> getRequiredValidators() { - return Collections.<ConsistencyValidator>singleton(new SystemSettingsValidator(systemManager)); + return Collections.emptySet(); }
} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/Importer.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/Importer.java index b61777d..a29e099 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/Importer.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/Importer.java @@ -19,11 +19,14 @@
package org.rhq.enterprise.server.sync.importers;
+import java.util.Set; + import javax.xml.stream.XMLStreamException;
import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.enterprise.server.sync.ExportReader; +import org.rhq.enterprise.server.sync.validators.EntityValidator;
/** * Implementations of this interface are used to import entities into the database. @@ -58,6 +61,12 @@ public interface Importer<Entity, ExportedType> { ExportedEntityMatcher<Entity, ExportedType> getExportedEntityMatcher();
/** + * The set of entity validators that should be called on each entity before + * the import actually starts. + */ + Set<EntityValidator<ExportedType>> getEntityValidators(); + + /** * Updates the entity with the data from the export. * <p> * This method is responsible for persisting the entity in the database @@ -84,6 +93,10 @@ public interface Importer<Entity, ExportedType> { * have been {@link #update(Object, Object) updated}. * <p> * This is useful for importers that need to batch the updates to the database. + * + * @return notes that should be transfered to the user. These should be any warnings and other + * messages that are not errors (which should throw an exception) but are deemed + * important for the (human) caller to be aware of. */ - void finishImport() throws Exception; + String finishImport() throws Exception; } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/MetricTemplateImporter.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/MetricTemplateImporter.java index 78eea09..f4fa3f5 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/MetricTemplateImporter.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/MetricTemplateImporter.java @@ -21,9 +21,13 @@ package org.rhq.enterprise.server.sync.importers;
import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet;
import javax.persistence.EntityManager; import javax.persistence.Query; @@ -51,6 +55,8 @@ import org.rhq.core.domain.measurement.MeasurementDefinition; import org.rhq.core.domain.sync.entity.MetricTemplate; import org.rhq.enterprise.server.measurement.MeasurementScheduleManagerLocal; import org.rhq.enterprise.server.sync.ExportReader; +import org.rhq.enterprise.server.sync.validators.EntityValidator; +import org.rhq.enterprise.server.sync.validators.UniquenessValidator; import org.rhq.enterprise.server.util.LookupUtil;
/** @@ -71,6 +77,8 @@ public class MetricTemplateImporter implements Importer<MeasurementDefinition, M public static final String METRIC_UPDATE_OVERRIDES_PROPERTY = "metricUpdateOverrides"; public static final String METRIC_UPDATE_OVERRIDE_PROPERTY = "metricUpdateOverride";
+ private static final String IMPORT_NOTES_PROLOGUE = "The following metric templates were not imported because they do not correspond to any metric defined by the existing resource types:\n"; + private static class UpdateKey { public final long collectionInterval; public final boolean updateSchedules; @@ -104,6 +112,26 @@ public class MetricTemplateImporter implements Importer<MeasurementDefinition, M } }
+ private static final Comparator<MetricTemplate> METRIC_TEMPLATE_COMPARATOR = new Comparator<MetricTemplate>() { + + @Override + public int compare(MetricTemplate o1, MetricTemplate o2) { + //sort by plugin, type name, and metric name in that order + + int ret = o1.getResourceTypePlugin().compareTo(o2.getResourceTypePlugin()); + if (ret != 0) { + return ret; + } + + ret = o1.getResourceTypeName().compareTo(o2.getResourceTypeName()); + if (ret != 0) { + return ret; + } + + return o1.getMetricName().compareTo(o2.getMetricName()); + } + }; + private Subject subject; private EntityManager entityManager; private Map<UpdateKey, List<MeasurementDefinition>> definitionsByUpdateKey = @@ -111,7 +139,8 @@ public class MetricTemplateImporter implements Importer<MeasurementDefinition, M private Configuration importConfiguration; private Unmarshaller unmarshaller; private MeasurementScheduleManagerLocal measurementScheduleManager; - + private Set<MetricTemplate> unmatchedTemplates = new TreeSet<MetricTemplate>(METRIC_TEMPLATE_COMPARATOR); + public MetricTemplateImporter(Subject subject, EntityManager entityManager) { this(subject, entityManager, LookupUtil.getMeasurementScheduleManager()); } @@ -215,8 +244,14 @@ public class MetricTemplateImporter implements Importer<MeasurementDefinition, M }
@Override + public Set<EntityValidator<MetricTemplate>> getEntityValidators() { + return Collections.<EntityValidator<MetricTemplate>>singleton(new UniquenessValidator<MetricTemplate>()); + } + + @Override public void update(MeasurementDefinition entity, MetricTemplate exportedEntity) { if (entity == null) { + unmatchedTemplates.add(exportedEntity); return; }
@@ -233,7 +268,7 @@ public class MetricTemplateImporter implements Importer<MeasurementDefinition, M }
@Override - public void finishImport() { + public String finishImport() { for (Map.Entry<UpdateKey, List<MeasurementDefinition>> e : definitionsByUpdateKey.entrySet()) { int[] ids = getIdsFromDefs(e.getValue()); boolean enable = e.getKey().enable; @@ -243,8 +278,25 @@ public class MetricTemplateImporter implements Importer<MeasurementDefinition, M measurementScheduleManager.updateDefaultCollectionIntervalAndEnablementForMeasurementDefinitions(subject, ids, collectionInterval, enable, updateSchedules); } + + if (unmatchedTemplates.isEmpty()) { + return null; + } else { + return getUnmatchedMetricTemplatesReport(unmatchedTemplates); + } }
+ //public for testability + public static String getUnmatchedMetricTemplatesReport(Set<MetricTemplate> metricTemplates) { + StringBuilder bld = new StringBuilder(IMPORT_NOTES_PROLOGUE); + + for(MetricTemplate t : metricTemplates) { + bld.append(t).append("\n"); + } + + return bld.toString(); + } + private static int[] getIdsFromDefs(Collection<MeasurementDefinition> defs) { int[] ids = new int[defs.size()];
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/SystemSettingsImporter.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/SystemSettingsImporter.java index 604196a..089746b 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/SystemSettingsImporter.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/importers/SystemSettingsImporter.java @@ -39,6 +39,9 @@ import org.rhq.core.domain.configuration.definition.PropertySimpleType; import org.rhq.core.domain.sync.entity.SystemSettings; import org.rhq.enterprise.server.sync.ExportReader; import org.rhq.enterprise.server.sync.NoSingleEntity; +import org.rhq.enterprise.server.sync.validators.EntityValidator; +import org.rhq.enterprise.server.sync.validators.MaxCountValidator; +import org.rhq.enterprise.server.sync.validators.SystemSettingsValidator; import org.rhq.enterprise.server.system.SystemManagerLocal;
/** @@ -100,6 +103,14 @@ public class SystemSettingsImporter implements Importer<NoSingleEntity, SystemSe }
@Override + public Set<EntityValidator<SystemSettings>> getEntityValidators() { + HashSet<EntityValidator<SystemSettings>> ret = new HashSet<EntityValidator<SystemSettings>>(); + ret.add(new SystemSettingsValidator()); + ret.add(new MaxCountValidator<SystemSettings>(1)); + return ret; + } + + @Override public void update(NoSingleEntity entity, SystemSettings exportedEntity) throws Exception { Properties props = exportedEntity.toProperties();
@@ -131,7 +142,8 @@ public class SystemSettingsImporter implements Importer<NoSingleEntity, SystemSe }
@Override - public void finishImport() { + public String finishImport() { + return null; }
private Set<String> getSettingNamesConfiguredForImport(Configuration importConfiguration) { diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/ConsistencyValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/ConsistencyValidator.java index 2b42f5a..30d2cd5 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/ConsistencyValidator.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/ConsistencyValidator.java @@ -19,8 +19,6 @@
package org.rhq.enterprise.server.sync.validators;
-import java.util.Set; - import javax.persistence.EntityManager; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -28,7 +26,6 @@ import javax.xml.stream.XMLStreamReader; import org.rhq.core.domain.auth.Subject; import org.rhq.enterprise.server.sync.ExportReader; import org.rhq.enterprise.server.sync.ExportWriter; -import org.rhq.enterprise.server.sync.ValidationException;
/** * Implementations of this interface can export a state and validate that @@ -90,37 +87,4 @@ public interface ConsistencyValidator { * @throws InconsistentStateException in case of failed consistency check */ void validateExportedState() throws InconsistentStateException; - - /** - * Returns the types of exported entities this validator can validate before export. - * This set can be empty, which would mean it can only validate the current state. - */ - Set<Class<?>> getValidatedEntityTypes(); - - /** - * Validates a single entity before it is imported. - * The supplied entity has one of the types returned by {@link #getValidatedEntityTypes()}. - * - * @param entity - */ - void validateExportedEntity(Object entity) throws ValidationException; - - /** - * Implementations of the consistency validator interface should reimplement the - * {@link Object#equals(Object)} method so that two identically configured - * validators are equal to each other. - * - * @param other - * @return - */ - boolean equals(Object other); - - /** - * The {@link ConsistencyValidator} interface mandates a certain behavior of - * the {@link #equals(Object)} method and therefore the <code>hashCode</code> - * should be reimplemented accordingly. - * - * @return - */ - int hashCode(); } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/DeployedAgentPluginsValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/DeployedAgentPluginsValidator.java index 2ec3f54..94fb4c3 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/DeployedAgentPluginsValidator.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/DeployedAgentPluginsValidator.java @@ -20,7 +20,6 @@ package org.rhq.enterprise.server.sync.validators;
import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -35,13 +34,15 @@ import org.rhq.core.domain.plugin.PluginDeploymentType; import org.rhq.enterprise.server.resource.metadata.PluginManagerLocal; import org.rhq.enterprise.server.sync.ExportReader; import org.rhq.enterprise.server.sync.ExportWriter; -import org.rhq.enterprise.server.sync.ValidationException; import org.rhq.enterprise.server.util.LookupUtil;
/** * This implementation checks that the two installations * have the exact same plugins deployed. * + * Note that this class is currently not used by any synchronizer but + * exists for "demo" purposes. + * * @author Lukas Krejci */ public class DeployedAgentPluginsValidator implements ConsistencyValidator { @@ -173,15 +174,6 @@ public class DeployedAgentPluginsValidator implements ConsistencyValidator { }
@Override - public Set<Class<?>> getValidatedEntityTypes() { - return Collections.emptySet(); - } - - @Override - public void validateExportedEntity(Object entity) throws ValidationException { - } - - @Override public int hashCode() { //all the deployed plugins validators are equal return 0; diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/EntityValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/EntityValidator.java new file mode 100644 index 0000000..1555f6f --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/EntityValidator.java @@ -0,0 +1,52 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.server.sync.validators; + +import javax.persistence.EntityManager; + +import org.rhq.core.domain.auth.Subject; +import org.rhq.enterprise.server.sync.ValidationException; + +/** + * Entity validators are declared by importers to validate the entities in the export + * file before it gets imported. + * + * @author Lukas Krejci + */ +public interface EntityValidator<T> { + + /** + * Initializes the validator with the current authentication info and access to database. + * This method is only called during import. + * + * @param subject the currently authenticated user + * @param entityManager the entity manager that can be used to access the database if the + * validator needs to do so. + */ + void initialize(Subject subject, EntityManager entityManager); + + /** + * Validates a single entity before it is imported. + * The supplied entity has one of the types returned by {@link #getValidatedEntityTypes()}. + * + * @param entity + */ + void validateExportedEntity(T entity) throws ValidationException; +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MaxCountValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MaxCountValidator.java new file mode 100644 index 0000000..3dfb5ec --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MaxCountValidator.java @@ -0,0 +1,52 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.server.sync.validators; + +import javax.persistence.EntityManager; + +import org.rhq.core.domain.auth.Subject; +import org.rhq.enterprise.server.sync.ValidationException; + +/** + * + * + * @author Lukas Krejci + */ +public class MaxCountValidator<T> implements EntityValidator<T> { + + private int max; + private int cnt; + + public MaxCountValidator(int max) { + this.max = max; + } + + @Override + public void initialize(Subject subject, EntityManager entityManager) { + cnt = 0; + } + + @Override + public void validateExportedEntity(T entity) throws ValidationException { + if (++cnt > max) { + throw new ValidationException("Entity " + entity + " is unexpected in the export file. At most " + max + " entites of this type are expected."); + } + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MetricTemplateValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MetricTemplateValidator.java deleted file mode 100644 index eddddf7..0000000 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/MetricTemplateValidator.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2011 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -package org.rhq.enterprise.server.sync.validators; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javax.persistence.EntityManager; -import javax.persistence.Query; -import javax.xml.stream.XMLStreamException; - -import org.rhq.core.domain.auth.Subject; -import org.rhq.core.domain.measurement.MeasurementDefinition; -import org.rhq.core.domain.sync.entity.MetricTemplate; -import org.rhq.enterprise.server.sync.ExportReader; -import org.rhq.enterprise.server.sync.ExportWriter; -import org.rhq.enterprise.server.sync.ValidationException; - -/** - * - * - * @author Lukas Krejci - */ -public class MetricTemplateValidator implements ConsistencyValidator { - - private EntityManager entityManager; - private Set<MetricTemplate> allMeasurementDefinitions; - private Set<MetricTemplate> alreadyCheckedTemplates; - private boolean dataInitialized = false; - - @Override - public void initialize(Subject subject, EntityManager entityManager) { - this.entityManager = entityManager; - } - - @Override - public void exportState(ExportWriter writer) throws XMLStreamException { - } - - @Override - public void initializeExportedStateValidation(ExportReader reader) throws XMLStreamException { - } - - @Override - public void validateExportedState() throws InconsistentStateException { - } - - @Override - public Set<Class<?>> getValidatedEntityTypes() { - return Collections.<Class<?>> singleton(MetricTemplate.class); - } - - @Override - public void validateExportedEntity(Object entity) throws ValidationException { - initializeData(); - - MetricTemplate template = (MetricTemplate) entity; - - if (!allMeasurementDefinitions.contains(template)) { - throw new ValidationException( - "The metric template " - + template - + " does not have any corresponding metric template in the database. This either means that the source of the export had different plugins installed, the export file has been manually edited to contain this inconsistency or that the database is corrupted."); - } - - if (!alreadyCheckedTemplates.add(template)) { - throw new ValidationException("Was the export file manually updated? The metric template " + template + " has been seen multiple times."); - } - } - - private void initializeData() { - if (dataInitialized) { - return; - } - - allMeasurementDefinitions = new HashSet<MetricTemplate>(); - alreadyCheckedTemplates = new HashSet<MetricTemplate>(); - - Query q = entityManager.createQuery("SELECT md FROM MeasurementDefinition md"); - - for (Object r : q.getResultList()) { - MeasurementDefinition md = (MeasurementDefinition) r; - - allMeasurementDefinitions.add(new MetricTemplate(md)); - } - - dataInitialized = true; - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - return other instanceof MetricTemplateValidator; - } -} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/SystemSettingsValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/SystemSettingsValidator.java index 1d34516..0698aa7 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/SystemSettingsValidator.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/SystemSettingsValidator.java @@ -19,16 +19,10 @@
package org.rhq.enterprise.server.sync.validators;
-import java.util.Collections; -import java.util.Set; - import javax.persistence.EntityManager; -import javax.xml.stream.XMLStreamException;
import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.sync.entity.SystemSettings; -import org.rhq.enterprise.server.sync.ExportReader; -import org.rhq.enterprise.server.sync.ExportWriter; import org.rhq.enterprise.server.sync.ValidationException; import org.rhq.enterprise.server.system.SystemManagerLocal; import org.rhq.enterprise.server.util.LookupUtil; @@ -38,7 +32,7 @@ import org.rhq.enterprise.server.util.LookupUtil; * * @author Lukas Krejci */ -public class SystemSettingsValidator implements ConsistencyValidator { +public class SystemSettingsValidator implements EntityValidator<SystemSettings> {
private Subject subject; private SystemManagerLocal systemManager; @@ -57,41 +51,11 @@ public class SystemSettingsValidator implements ConsistencyValidator { }
@Override - public void exportState(ExportWriter writer) throws XMLStreamException { - } - - @Override - public void initializeExportedStateValidation(ExportReader reader) throws XMLStreamException { - } - - @Override - public void validateExportedState() throws InconsistentStateException { - } - - @Override - public Set<Class<?>> getValidatedEntityTypes() { - return Collections.<Class<?>>singleton(SystemSettings.class); - } - - @Override - public void validateExportedEntity(Object entity) throws ValidationException { - if (entity instanceof SystemSettings) { - try { - systemManager.validateSystemConfiguration(subject, ((SystemSettings)entity).toProperties()); - } catch (Exception e) { - throw new ValidationException("The system settings failed to validate: " + e.getMessage(), e); - } + public void validateExportedEntity(SystemSettings entity) throws ValidationException { + try { + systemManager.validateSystemConfiguration(subject, ((SystemSettings)entity).toProperties()); + } catch (Exception e) { + throw new ValidationException("The system settings failed to validate: " + e.getMessage(), e); } } - - @Override - public int hashCode() { - return 0; //all system settings validators are equal - } - - @Override - public boolean equals(Object obj) { - //all system settings validators are equal - return obj instanceof SystemSettingsValidator; - } } diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/UniquenessValidator.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/UniquenessValidator.java new file mode 100644 index 0000000..7fc56f5 --- /dev/null +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/sync/validators/UniquenessValidator.java @@ -0,0 +1,50 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.server.sync.validators; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.EntityManager; + +import org.rhq.core.domain.auth.Subject; +import org.rhq.enterprise.server.sync.ValidationException; + +/** + * This validator merely checks that there are no duplicates in the export file. + * + * @author Lukas Krejci + */ +public class UniquenessValidator<T> implements EntityValidator<T> { + + private Set<T> alreadyCheckedEntities; + + @Override + public void initialize(Subject subject, EntityManager entityManager) { + alreadyCheckedEntities = new HashSet<T>(); + } + + @Override + public void validateExportedEntity(T entity) throws ValidationException { + if (!alreadyCheckedEntities.add(entity)) { + throw new ValidationException("Was the export file manually updated? The entity " + entity + " has been seen multiple times."); + } + } +} diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java index aef8879..1cb14b2 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/webservices/WebservicesManagerBean.java @@ -125,6 +125,7 @@ import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite; import org.rhq.core.domain.sync.ExportReport; import org.rhq.core.domain.sync.ImportConfiguration; import org.rhq.core.domain.sync.ImportConfigurationDefinition; +import org.rhq.core.domain.sync.ImportReport; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.server.alert.AlertDefinitionManagerLocal; @@ -1222,9 +1223,9 @@ public class WebservicesManagerBean implements WebservicesRemote { return synchronizationManager.getImportConfigurationDefinition(importerClass); }
- public void importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> importerConfigurations) + public ImportReport importAllSubsystems(Subject subject, byte[] exportFile, List<ImportConfiguration> importerConfigurations) throws ValidationException, ImportException { - synchronizationManager.importAllSubsystems(subject, exportFile, importerConfigurations); + return synchronizationManager.importAllSubsystems(subject, exportFile, importerConfigurations); }
//SYNCHRONIZATIONMANANGER: END ------------------------- diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/DeployedAgentPluginsValidatorTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/DeployedAgentPluginsValidatorTest.java index 133750d..061d803 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/DeployedAgentPluginsValidatorTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/DeployedAgentPluginsValidatorTest.java @@ -54,7 +54,8 @@ import org.rhq.test.JMockTest; * * @author Lukas Krejci */ -@Test +//@Test - switching this off for now because this validator is no longer used in any +//of the default synchronizers public class DeployedAgentPluginsValidatorTest extends JMockTest {
private static final Log LOG = LogFactory.getLog(DeployedAgentPluginsValidator.class); diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/ExportingInputStreamTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/ExportingInputStreamTest.java index 975e6d3..6d56969 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/ExportingInputStreamTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/ExportingInputStreamTest.java @@ -65,6 +65,7 @@ import org.rhq.enterprise.server.sync.exporters.ExportingIterator; import org.rhq.enterprise.server.sync.importers.ExportedEntityMatcher; import org.rhq.enterprise.server.sync.importers.Importer; import org.rhq.enterprise.server.sync.validators.ConsistencyValidator; +import org.rhq.enterprise.server.sync.validators.EntityValidator; import org.rhq.test.JMockTest;
/** @@ -140,7 +141,13 @@ public class ExportingInputStreamTest extends JMockTest { }
@Override - public void finishImport() throws Exception { + public String finishImport() throws Exception { + return null; + } + + @Override + public Set<EntityValidator<T>> getEntityValidators() { + return Collections.emptySet(); }
} diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MaxCountValidatorTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MaxCountValidatorTest.java new file mode 100644 index 0000000..b18662b --- /dev/null +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MaxCountValidatorTest.java @@ -0,0 +1,52 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.server.sync.test; + +import static org.testng.Assert.fail; + +import org.testng.annotations.Test; + +import org.rhq.enterprise.server.sync.ValidationException; +import org.rhq.enterprise.server.sync.validators.MaxCountValidator; + +/** + * + * + * @author Lukas Krejci + */ +@Test +public class MaxCountValidatorTest { + + public void testThrowsValidationExceptionAfterMaxEntitiesValidated() { + MaxCountValidator<String> validator = new MaxCountValidator<String>(3); + + validator.initialize(null, null); + + validator.validateExportedEntity("1"); + validator.validateExportedEntity("2"); + validator.validateExportedEntity("3"); + try { + validator.validateExportedEntity("4"); + fail("The max count validator shouldn't have accepted the 4th entry."); + } catch (ValidationException e) { + //expected + } + } +} diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateExporterTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateExporterTest.java index 34de39e..6987001 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateExporterTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateExporterTest.java @@ -22,13 +22,10 @@ package org.rhq.enterprise.server.sync.test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue;
-import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -49,7 +46,6 @@ import org.w3c.dom.NodeList; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.criteria.MeasurementDefinitionCriteria; import org.rhq.core.domain.measurement.MeasurementDefinition; -import org.rhq.core.domain.plugin.Plugin; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.sync.ExporterMessages; @@ -57,7 +53,6 @@ import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.server.measurement.MeasurementDefinitionManagerLocal; import org.rhq.enterprise.server.measurement.MeasurementScheduleManagerLocal; -import org.rhq.enterprise.server.resource.metadata.PluginManagerLocal; import org.rhq.enterprise.server.sync.ExportingInputStream; import org.rhq.enterprise.server.sync.MetricTemplateSynchronizer; import org.rhq.enterprise.server.sync.SynchronizationConstants; @@ -77,19 +72,15 @@ public class MetricTemplateExporterTest extends JMockTest {
public void testCanExport() throws Exception { final MeasurementDefinitionManagerLocal measurementDefinitionManager = context.mock(MeasurementDefinitionManagerLocal.class); - final PluginManagerLocal pluginManager = context.mock(PluginManagerLocal.class); final MeasurementScheduleManagerLocal measurementScheduleManager = context.mock(MeasurementScheduleManagerLocal.class); context.checking(new Expectations() { { allowing(measurementDefinitionManager).findMeasurementDefinitionsByCriteria(with(any(Subject.class)), with(any(MeasurementDefinitionCriteria.class))); will(returnValue(getFakeMeasurementDefinitions())); - - allowing(pluginManager).getInstalledPlugins(); - will(returnValue(getFakeInstalledPlugins())); } });
- MetricTemplateSynchronizer exporter = new MetricTemplateSynchronizer(measurementDefinitionManager, measurementScheduleManager, pluginManager); + MetricTemplateSynchronizer exporter = new MetricTemplateSynchronizer(measurementDefinitionManager, measurementScheduleManager);
Set<Synchronizer<?, ?>> exporters = new HashSet<Synchronizer<?, ?>>(); exporters.add(exporter); @@ -227,10 +218,4 @@ public class MetricTemplateExporterTest extends JMockTest {
return new PageList<MeasurementDefinition>(ret, PageControl.getUnlimitedInstance()); } - - private static List<Plugin> getFakeInstalledPlugins() { - Plugin p = new Plugin("fakePlugin", null, "12345"); - p.setVersion("1.0.0.test"); - return Collections.singletonList(p); - } } diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateImporterTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateImporterTest.java index 7b50340..8c615b4 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateImporterTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateImporterTest.java @@ -21,6 +21,7 @@ package org.rhq.enterprise.server.sync.test;
import static org.testng.Assert.assertNull; import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertEquals;
import java.util.Arrays; import java.util.Collections; @@ -98,7 +99,6 @@ public class MetricTemplateImporterTest extends JMockTest { private static final ResourceType FAKE_RESOURCE_TYPE = new ResourceType("fake", "fake", ResourceCategory.PLATFORM, null);
- @SuppressWarnings("unchecked") public void testNonMatchingMeasurementDefinitionsAreIgnored() { final TestPrerequisities prereqs = new TestPrerequisities(context);
@@ -156,7 +156,6 @@ public class MetricTemplateImporterTest extends JMockTest { importer.finishImport(); }
- @SuppressWarnings("unchecked") public void testCanUpdateEnablements() { MeasurementDefinition defToEnable = new MeasurementDefinition(FAKE_RESOURCE_TYPE, "enabled"); MeasurementDefinition defToDisable = new MeasurementDefinition(FAKE_RESOURCE_TYPE, "disable"); @@ -210,7 +209,6 @@ public class MetricTemplateImporterTest extends JMockTest {
}
- @SuppressWarnings("unchecked") public void testCanUpdateSchedules() { MeasurementDefinition def = new MeasurementDefinition(FAKE_RESOURCE_TYPE, "def"); def.setId(1); @@ -253,7 +251,6 @@ public class MetricTemplateImporterTest extends JMockTest { importer.finishImport(); }
- @SuppressWarnings("unchecked") public void testPerMetricUpdateScheduleOverrides() { MeasurementDefinition updatedDef = new MeasurementDefinition(FAKE_RESOURCE_TYPE, "def"); updatedDef.setId(1); @@ -325,7 +322,6 @@ public class MetricTemplateImporterTest extends JMockTest { testNonMatchingMeasurementDefinitionsAreIgnored(); }
- @SuppressWarnings("unchecked") public void testDistinguishingBetweenNormalAndPerMinuteTemplates() { MeasurementDefinition normalDef = new MeasurementDefinition(FAKE_RESOURCE_TYPE, "def"); MeasurementDefinition perMinuteDef = new MeasurementDefinition(FAKE_RESOURCE_TYPE, "def"); @@ -377,4 +373,40 @@ public class MetricTemplateImporterTest extends JMockTest { //correctly by the importer. importer.finishImport(); } + + public void testNotifiesAboutIgnoredMetricTemplates() throws Exception { + final TestPrerequisities prereqs = new TestPrerequisities(context); + prereqs.setMeasurementDefinitions(Collections.<MeasurementDefinition>emptyList()); + + context.checking(new Expectations() { + { + prereqs.addExpectations(this); + } + }); + + MetricTemplateImporter importer = + new MetricTemplateImporter(null, prereqs.getEntityManager(), prereqs.getMeasurementScheduleManager()); + + importer.configure(null); + + importer.configure(null); + + MetricTemplate unmatched = new MetricTemplate(); + unmatched.setMetricName("made-up"); + unmatched.setResourceTypeName("made-up"); + unmatched.setResourceTypePlugin("made-up"); + + ExportedEntityMatcher<MeasurementDefinition, MetricTemplate> matcher = importer.getExportedEntityMatcher(); + + assertNull(matcher.findMatch(unmatched)); + + importer.update(null, unmatched); + + String notes = importer.finishImport(); + + String expectedNotes = + MetricTemplateImporter.getUnmatchedMetricTemplatesReport(Collections.singleton(unmatched)); + + assertEquals(notes, expectedNotes); + } } diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateValidatorTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateValidatorTest.java deleted file mode 100644 index 3afe29f..0000000 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/MetricTemplateValidatorTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2005-2011 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -package org.rhq.enterprise.server.sync.test; - -import static org.testng.Assert.*; - -import java.util.ArrayList; -import java.util.List; - -import javax.persistence.EntityManager; -import javax.persistence.Query; - -import org.jmock.Expectations; -import org.testng.annotations.Test; - -import org.rhq.core.domain.measurement.MeasurementDefinition; -import org.rhq.core.domain.measurement.NumericType; -import org.rhq.core.domain.resource.ResourceCategory; -import org.rhq.core.domain.resource.ResourceType; -import org.rhq.core.domain.sync.entity.MetricTemplate; -import org.rhq.enterprise.server.sync.ValidationException; -import org.rhq.enterprise.server.sync.validators.MetricTemplateValidator; -import org.rhq.test.JMockTest; - -/** - * - * - * @author Lukas Krejci - */ -@Test -public class MetricTemplateValidatorTest extends JMockTest { - - private static final ResourceType FAKE_RESOURCE_TYPE = new ResourceType("fake", "fake", ResourceCategory.PLATFORM, null); - - public void testAllValidatorsEqual() { - MetricTemplateValidator v1 = new MetricTemplateValidator(); - MetricTemplateValidator v2 = new MetricTemplateValidator(); - MetricTemplateValidator v3 = new MetricTemplateValidator(); - - assertEquals(v1, v2); - assertEquals(v2, v3); - assertEquals(v1, v3); - } - - public void testDetectsUnknownTemplates() throws Exception { - final EntityManager entityManager = context.mock(EntityManager.class); - final Query q = context.mock(Query.class); - - final List<MeasurementDefinition> allDefs = new ArrayList<MeasurementDefinition>(); - - context.checking(new Expectations() { - { - //make the entity manager return the test data - allowing(entityManager).createQuery(with(any(String.class))); - will(returnValue(q)); - - allowing(q).getResultList(); - will(returnValue(allDefs)); - } - }); - - //add some test data - allDefs.add(createMeasurementDefinition("m1", false)); - allDefs.add(createMeasurementDefinition("m1", true)); - allDefs.add(createMeasurementDefinition("m2", false)); - allDefs.add(createMeasurementDefinition("m3", false)); - - MetricTemplateValidator validator = new MetricTemplateValidator(); - - validator.initialize(null, entityManager); - validator.initializeExportedStateValidation(null); - - //check that all the defined measurement defs pass - for(MeasurementDefinition md : allDefs) { - validator.validateExportedEntity(new MetricTemplate(md)); - } - - //now let's create an "unknown" metric template - MetricTemplate unknown = new MetricTemplate(); - unknown.setMetricName("unknown"); - unknown.setResourceTypeName("some"); - unknown.setResourceTypePlugin("other"); - - try { - validator.validateExportedEntity(unknown); - fail("Validating a metric template " + unknown + " should have failed."); - } catch (ValidationException e) { - //expected - } - } - - public void testDetectsDuplicitEntries() throws Exception { - final EntityManager entityManager = context.mock(EntityManager.class); - final Query q = context.mock(Query.class); - - final List<MeasurementDefinition> allDefs = new ArrayList<MeasurementDefinition>(); - - context.checking(new Expectations() { - { - //make the entity manager return the test data - allowing(entityManager).createQuery(with(any(String.class))); - will(returnValue(q)); - - allowing(q).getResultList(); - will(returnValue(allDefs)); - } - }); - - //add some test data - allDefs.add(createMeasurementDefinition("m1", false)); - allDefs.add(createMeasurementDefinition("m1", true)); - allDefs.add(createMeasurementDefinition("m2", false)); - allDefs.add(createMeasurementDefinition("m3", false)); - - MetricTemplateValidator validator = new MetricTemplateValidator(); - - validator.initialize(null, entityManager); - validator.initializeExportedStateValidation(null); - - //check that all the defined measurement defs pass - for(MeasurementDefinition md : allDefs) { - validator.validateExportedEntity(new MetricTemplate(md)); - } - - //now let's try and validate the first test data again. - //this simulates the duplicate entries in the export file - try { - MetricTemplate duplicate = new MetricTemplate(allDefs.get(0)); - validator.validateExportedEntity(duplicate); - fail("Validating a duplicate metric template " + duplicate + " should have failed."); - } catch (ValidationException e) { - //expected - } - } - - private static MeasurementDefinition createMeasurementDefinition(String name, boolean perMinute) { - MeasurementDefinition ret = new MeasurementDefinition(FAKE_RESOURCE_TYPE, name); - if (perMinute) { - ret.setRawNumericType(NumericType.TRENDSUP); - } - - return ret; - } -} diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java index c5a0b2e..41f9a56 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SynchronizationManagerBeanTest.java @@ -27,7 +27,9 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.StringWriter; +import java.io.UnsupportedEncodingException; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -37,6 +39,8 @@ import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream;
import javax.persistence.EntityManager; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLStreamException; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; @@ -56,6 +60,8 @@ import org.w3c.dom.Element; import org.xml.sax.InputSource;
import org.rhq.core.domain.auth.Subject; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; import org.rhq.core.domain.criteria.MeasurementDefinitionCriteria; import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.measurement.DataType; @@ -76,10 +82,22 @@ import org.rhq.enterprise.server.authz.PermissionException; import org.rhq.enterprise.server.measurement.MeasurementDefinitionManagerLocal; import org.rhq.enterprise.server.measurement.MeasurementScheduleManagerLocal; import org.rhq.enterprise.server.resource.ResourceManagerLocal; +import org.rhq.enterprise.server.sync.ExportReader; +import org.rhq.enterprise.server.sync.ExportWriter; import org.rhq.enterprise.server.sync.MetricTemplateSynchronizer; +import org.rhq.enterprise.server.sync.NoSingleEntity; import org.rhq.enterprise.server.sync.SynchronizationConstants; import org.rhq.enterprise.server.sync.SynchronizationManagerLocal; +import org.rhq.enterprise.server.sync.Synchronizer; +import org.rhq.enterprise.server.sync.SynchronizerFactory; import org.rhq.enterprise.server.sync.SystemSettingsSynchronizer; +import org.rhq.enterprise.server.sync.ValidationException; +import org.rhq.enterprise.server.sync.exporters.Exporter; +import org.rhq.enterprise.server.sync.exporters.ExportingIterator; +import org.rhq.enterprise.server.sync.importers.ExportedEntityMatcher; +import org.rhq.enterprise.server.sync.importers.Importer; +import org.rhq.enterprise.server.sync.validators.ConsistencyValidator; +import org.rhq.enterprise.server.sync.validators.EntityValidator; import org.rhq.enterprise.server.system.SystemManagerLocal; import org.rhq.enterprise.server.test.AbstractEJB3Test; import org.rhq.enterprise.server.test.TestServerPluginService; @@ -108,12 +126,142 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { public TestServerPluginService testServerPluginService; }
+ //this can't be mocked out because the config sync machinery has to be able to + //instantiate this class + public static class ImportConfigurationCheckingSynchronizer implements Synchronizer<NoSingleEntity, String> { + + public static boolean importerConfigured; + public static boolean importValidatorsObtainedAfterConfiguration; + + public static void reset() { + importerConfigured = false; + importValidatorsObtainedAfterConfiguration = false; + } + + @Override + public void initialize(Subject subject, EntityManager entityManager) { + } + + @Override + public Exporter<NoSingleEntity, String> getExporter() { + return new Exporter<NoSingleEntity, String>() { + + @Override + public ExportingIterator<String> getExportingIterator() { + return new ExportingIterator<String>() { + boolean ran = false; + + @Override + public boolean hasNext() { + if (ran) { + return false; + } + + ran = true; + return true; + } + + @Override + public String next() { + return null; + } + + @Override + public void remove() { + } + + @Override + public void export(ExportWriter output) throws XMLStreamException { + output.writeStartElement("my-entity"); + output.writeCharacters("value"); + output.writeEndElement(); + } + + @Override + public String getNotes() { + return null; + } + + }; + } + + @Override + public String getNotes() { + return null; + } + + }; + } + + @Override + public Importer<NoSingleEntity, String> getImporter() { + return new Importer<NoSingleEntity, String>() { + + @Override + public ConfigurationDefinition getImportConfigurationDefinition() { + return new ConfigurationDefinition("fake", null); + } + + @Override + public void configure(Configuration importConfiguration) { + importerConfigured = true; + } + + @Override + public ExportedEntityMatcher<NoSingleEntity, String> getExportedEntityMatcher() { + return null; + } + + @Override + public Set<EntityValidator<String>> getEntityValidators() { + EntityValidator<String> v = new EntityValidator<String>() { + + @Override + public void validateExportedEntity(String entity) throws ValidationException { + } + + @Override + public void initialize(Subject subject, EntityManager entityManager) { + } + }; + + if (importerConfigured) { + importValidatorsObtainedAfterConfiguration = true; + } + + return Collections.singleton(v); + } + + @Override + public void update(NoSingleEntity entity, String exportedEntity) throws Exception { + } + + @Override + public String unmarshallExportedEntity(ExportReader reader) throws XMLStreamException { + return reader.getElementText(); + } + + @Override + public String finishImport() throws Exception { + return null; + } + + }; + } + + @Override + public Set<ConsistencyValidator> getRequiredValidators() { + return Collections.emptySet(); + } + + } + private TestData testData;
//I just don't get why this can't be a @BeforeTest //but when it was declared as such (together with tearDown() being an @AfterTest) //no tests would work. I have no idea why... - private void setup() throws Exception { + private void setup(boolean createExport) throws Exception { testData = new TestData(); getTransactionManager().begin(); try { @@ -154,7 +302,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { testData.testServerPluginService = new TestServerPluginService(); prepareCustomServerPluginService(testData.testServerPluginService); testData.testServerPluginService.startMasterPluginContainer(); - + synchronizationManager = LookupUtil.getSynchronizationManager();
SystemManagerLocal systemManager = LookupUtil.getSystemManager(); @@ -162,7 +310,10 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { systemManager.loadSystemConfigurationCache();
testData.systemSettings = systemManager.getSystemConfiguration(freshUser()); - export = synchronizationManager.exportAllSubsystems(freshUser()); + + if (createExport) { + export = synchronizationManager.exportAllSubsystems(freshUser()); + } }
private void tearDown() throws Exception { @@ -183,7 +334,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { em.remove(attachedType);
em.flush(); - + getTransactionManager().commit(); } catch (Exception e) { getTransactionManager().rollback(); @@ -192,14 +343,14 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test {
unprepareServerPluginService(); testData.testServerPluginService.stopMasterPluginContainer(); - + export = null; testData = null; synchronizationManager = null; }
public void testExport() throws Exception { - setup(); + setup(true); try { assertNull("Export shouldn't generate an error message.", export.getErrorMessage()); assertTrue("The export should contain some data.", export.getExportFile().length > 0); @@ -209,7 +360,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { }
public void testImportWithDefaultConfiguration() throws Exception { - setup(); + setup(true);
try { SystemManagerLocal systemManager = LookupUtil.getSystemManager(); @@ -247,7 +398,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { }
public void testImportWithRedefinedConfigurationInExportFile() throws Exception { - setup(); + setup(true);
try { String exportXML = getExportData(); @@ -255,15 +406,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { exportXML = updateSystemSettingsImportConfiguration(exportXML); exportXML = updateMetricTemplatesImportConfiguration(exportXML);
- ByteArrayOutputStream compressed = new ByteArrayOutputStream(); - OutputStreamWriter wrt = new OutputStreamWriter(new GZIPOutputStream(compressed), "UTF-8"); - try { - wrt.write(exportXML); - } finally { - wrt.close(); - } - - InputStream exportData = new ByteArrayInputStream(compressed.toByteArray()); + InputStream exportData = createCompressedStream(exportXML);
try { synchronizationManager.importAllSubsystems(freshUser(), exportData, null); @@ -317,7 +460,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { }
public void testManuallyPassedImportConfigurationHasPrecendenceOverTheInlinedOne() throws Exception { - setup(); + setup(true);
try { //let's read the original values from the database, so that we know what to compare against @@ -342,15 +485,7 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { exportXML = updateSystemSettingsImportConfiguration(exportXML); exportXML = updateMetricTemplatesImportConfiguration(exportXML);
- ByteArrayOutputStream compressed = new ByteArrayOutputStream(); - OutputStreamWriter wrt = new OutputStreamWriter(new GZIPOutputStream(compressed), "UTF-8"); - try { - wrt.write(exportXML); - } finally { - wrt.close(); - } - - InputStream exportData = new ByteArrayInputStream(compressed.toByteArray()); + InputStream exportData = createCompressedStream(exportXML);
//let's just use the default configs so that we don't apply the changes suggested in //the changed default configs created above @@ -408,6 +543,58 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { } }
+ public void testUnknownValidatorsAreIgnored() throws Exception { + setup(true); + + try { + String export = getExportData(); + + Document xml = + DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(new InputSource(new StringReader(export))); + + Element unknownValidator = xml.createElement("validator"); + unknownValidator.setAttribute(SynchronizationConstants.CLASS_ATTRIBUTE, "org.nothing.UnknownValidator"); + + xml.getDocumentElement().insertBefore(unknownValidator, xml.getDocumentElement().getFirstChild()); + + export = documentToString(xml); + + InputStream exportStream = createCompressedStream(export); + + synchronizationManager.importAllSubsystems(freshUser(), exportStream, null); + } finally { + tearDown(); + } + } + + public void testImporterConfiguredBeforeValidatorsObtained() throws Exception { + setup(false); + + try { + ImportConfigurationCheckingSynchronizer.reset(); + + synchronizationManager.setSynchronizerFactory(new SynchronizerFactory() { + @Override + public Set<Synchronizer<?, ?>> getAllSynchronizers() { + return Collections.<Synchronizer<?, ?>>singleton(new ImportConfigurationCheckingSynchronizer()); + } + }); + + export = synchronizationManager.exportAllSubsystems(freshUser()); + + //and import it back again, so that we actually invoke the import validation + synchronizationManager.importAllSubsystems(freshUser(), export.getExportFile(), null); + + assertTrue(ImportConfigurationCheckingSynchronizer.importerConfigured); + assertTrue(ImportConfigurationCheckingSynchronizer.importValidatorsObtainedAfterConfiguration); + } finally { + //reset the factory so that other tests work w/ the default syncers + synchronizationManager.setSynchronizerFactory(new SynchronizerFactory()); + tearDown(); + } + } + private String getExportData() throws IOException { InputStreamReader str = new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(export.getExportFile())), "UTF-8"); @@ -543,4 +730,16 @@ public class SynchronizationManagerBeanTest extends AbstractEJB3Test { user = subjectManager.getOverlord(); return user; } + + private InputStream createCompressedStream(String exportData) throws UnsupportedEncodingException, IOException { + ByteArrayOutputStream compressed = new ByteArrayOutputStream(); + OutputStreamWriter wrt = new OutputStreamWriter(new GZIPOutputStream(compressed), "UTF-8"); + try { + wrt.write(exportData); + } finally { + wrt.close(); + } + + return new ByteArrayInputStream(compressed.toByteArray()); + } } diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsImporterTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsImporterTest.java index 5b94450..711fb75 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsImporterTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsImporterTest.java @@ -20,7 +20,6 @@ package org.rhq.enterprise.server.sync.test;
import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Properties; diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsValidatorTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsValidatorTest.java index c00cb07..0966080 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsValidatorTest.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/SystemSettingsValidatorTest.java @@ -19,9 +19,6 @@
package org.rhq.enterprise.server.sync.test;
-import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; - import java.util.Properties;
import org.jmock.Expectations; @@ -58,22 +55,5 @@ public class SystemSettingsValidatorTest extends JMockTest { });
validator.validateExportedEntity(importedSettings); - } - - public void testAllValidatorsAreEqual() { - SystemManagerLocal systemManager = context.mock(SystemManagerLocal.class); - - SystemSettingsValidator v1 = new SystemSettingsValidator(systemManager); - SystemSettingsValidator v2 = new SystemSettingsValidator(systemManager); - SystemSettingsValidator v3 = new SystemSettingsValidator(systemManager); - Object o = new Object(); - - assertEquals(v1, v2); - assertEquals(v1, v3); - assertEquals(v2, v3); - - assertFalse(v1.equals(o)); - assertFalse(v2.equals(o)); - assertFalse(v3.equals(o)); - } + } } diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/UniquenessValidatorTest.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/UniquenessValidatorTest.java new file mode 100644 index 0000000..33a0207 --- /dev/null +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/sync/test/UniquenessValidatorTest.java @@ -0,0 +1,51 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2011 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.enterprise.server.sync.test; + +import static org.testng.Assert.fail; + +import org.testng.annotations.Test; + +import org.rhq.enterprise.server.sync.ValidationException; +import org.rhq.enterprise.server.sync.validators.UniquenessValidator; + +/** + * + * + * @author Lukas Krejci + */ +@Test +public class UniquenessValidatorTest { + + public void testDetectsDuplicitEntries() throws Exception { + UniquenessValidator<String> validator = new UniquenessValidator<String>(); + + validator.initialize(null, null); + + validator.validateExportedEntity("1"); + validator.validateExportedEntity("2"); + try { + validator.validateExportedEntity("1"); + fail("Uniqueness validator should have detected a duplicate entry."); + } catch (ValidationException e) { + //expected + } + } +}