/*
* RHQ Management Platform
* Copyright (C) 2005-2008 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.content.metadata;
import java.util.HashSet;
import java.util.Set;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.content.ContentSource;
import org.rhq.core.domain.content.ContentSourceType;
import org.rhq.enterprise.server.RHQConstants;
import org.rhq.enterprise.server.configuration.metadata.ConfigurationMetadataManagerLocal;
/**
* Used to work with metadata defining content source types.
*/
@Stateless
public class ContentSourceMetadataManagerBean implements ContentSourceMetadataManagerLocal {
private final Log log = LogFactory.getLog(ContentSourceMetadataManagerBean.class);
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@EJB
private ConfigurationMetadataManagerLocal configurationMetadataManager;
public void registerTypes(Set<ContentSourceType> typesToRegister) {
Set<ContentSourceType> existingTypes = new HashSet<ContentSourceType>();
Query q = entityManager.createNamedQuery(ContentSourceType.QUERY_FIND_ALL);
existingTypes.addAll(q.getResultList());
Set<ContentSourceType> typesToPersist = missingInFirstSet(existingTypes, typesToRegister);
Set<ContentSourceType> typesToDelete = missingInFirstSet(typesToRegister, existingTypes);
Set<ContentSourceType> typesToUpdate = intersection(existingTypes, typesToRegister); // order of params is important
// persist any types that need to be registered but do not currently exist
for (ContentSourceType typeToPersist : typesToPersist) {
entityManager.persist(typeToPersist);
}
// Remove any types that currently exist but are not in the types to register.
// Note that we only remove types that have no content sources associated with them.
// If someone removes a plugin but fails to delete content sources associate with their types,
// then we spit out a warning but leave the type definition in the database.
for (ContentSourceType typeToDelete : typesToDelete) {
Set<ContentSource> attachedSources = typeToDelete.getContentSources();
if ((attachedSources == null) || (attachedSources.size() == 0)) {
entityManager.remove(typeToDelete);
} else {
log.warn(typeToDelete.toString() + " is no longer supported by any deployed plugin, "
+ "but it still has some content sources associated with it. "
+ "Those content sources will no longer work.");
}
}
// we now have to merge existing types with their new definitions
for (ContentSourceType typeToUpdate : typesToUpdate) {
for (ContentSourceType typeToRegister : typesToRegister) {
if (typeToRegister.equals(typeToUpdate)) {
typeToUpdate.setDisplayName(typeToRegister.getDisplayName());
typeToUpdate.setDescription(typeToRegister.getDescription());
typeToUpdate.setContentSourceApiClass(typeToRegister.getContentSourceApiClass());
typeToUpdate.setDefaultSyncSchedule(typeToRegister.getDefaultSyncSchedule());
typeToUpdate.setDefaultLazyLoad(typeToRegister.isDefaultLazyLoad());
typeToUpdate.setDefaultDownloadMode(typeToRegister.getDefaultDownloadMode());
updateConfigurationDefinition(typeToRegister, typeToUpdate);
break;
}
}
}
return;
}
private void updateConfigurationDefinition(ContentSourceType newType, ContentSourceType existingType) {
ConfigurationDefinition newConfigDef = newType.getContentSourceConfigurationDefinition();
ConfigurationDefinition existingConfigDef = existingType.getContentSourceConfigurationDefinition();
if (newConfigDef != null) {
if (existingConfigDef == null) {
// everything is new
entityManager.persist(newConfigDef);
existingType.setContentSourceConfigurationDefinition(newConfigDef);
} else {
// both new and existing had some kind of configuration, update the existing to match the new
configurationMetadataManager.updateConfigurationDefinition(newConfigDef, existingConfigDef);
}
} else {
// the new config is null -> remove the existing config
if (existingConfigDef != null) {
existingType.setContentSourceConfigurationDefinition(null);
entityManager.remove(existingConfigDef);
}
}
return;
}
/**
* Return a set containing those element that are in reference, but not in first. Both input sets are not modified
*
* @param first
* @param reference
*
* @return
*/
private <T> Set<T> missingInFirstSet(Set<T> first, Set<T> reference) {
Set<T> result = new HashSet<T>();
if (reference != null) {
// First collection is null -> everything is missing
if (first == null) {
result.addAll(reference);
return result;
}
// else loop over the set and sort out the right items.
for (T item : reference) {
if (!first.contains(item)) {
result.add(item);
}
}
}
return result;
}
/**
* Return a new Set with elements both in first and second passed collection.
*
* @param first First set
* @param second Second set
*
* @return a new set (depending on input type) with elements in first and second
*/
private <T> Set<T> intersection(Set<T> first, Set<T> second) {
Set<T> result = new HashSet<T>();
if ((first != null) && (second != null)) {
result.addAll(first);
result.retainAll(second);
}
return result;
}
}