/*
* gvNIX is an open source tool for rapid application development (RAD).
* Copyright (C) 2010 Generalitat Valenciana
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
package org.gvnix.addon.jpa.addon.entitylistener;
import java.util.List;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.jpa.addon.activerecord.JpaActiveRecordMetadata;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.metadata.MetadataDependencyRegistry;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.metadata.MetadataItem;
import org.springframework.roo.metadata.MetadataNotificationListener;
import org.springframework.roo.metadata.MetadataProvider;
import org.springframework.roo.metadata.MetadataService;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.support.logging.HandlerUtils;
/**
* Metadata listener which handles metadata reltated to jpa entity listeners
*
* @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a
* href="http://www.dgti.gva.es">General Directorate for Information
* Technologies (DGTI)</a>
*/
@Component
@Service
public class JpaOrmEntityListenerMetadataListener implements MetadataProvider,
MetadataNotificationListener {
protected final static Logger LOGGER = HandlerUtils
.getLogger(JpaOrmEntityListenerMetadataListener.class);
// ------------ OSGi component attributes ----------------
private BundleContext context;
private MetadataDependencyRegistry metadataDependencyRegistry;
private MetadataService metadataService;
private JpaOrmEntityListenerRegistry registry;
private JpaOrmEntityListenerOperations operations;
protected void activate(final ComponentContext cContext) {
context = cContext.getBundleContext();
// We don't need register anything: this is done on
// JpaOrmEntityListenerRegistry
getMetadataDependencyRegistry().addNotificationListener(this);
}
protected void deactivate(final ComponentContext context) {
// We don't need register anything: this is done on
// JpaOrmEntityListenerRegistry
getMetadataDependencyRegistry().removeNotificationListener(this);
}
public MetadataItem get(final String jpaOrmEntityListenerMetadataId) {
// Get listener java type
final JavaType listenerJavaType = JpaOrmEntityListenerMetadata
.getJavaType(jpaOrmEntityListenerMetadataId);
final LogicalPath listenerPath = JpaOrmEntityListenerMetadata
.getPath(jpaOrmEntityListenerMetadataId);
// Locate source metadata
final String sourceMetadataProvider = JpaOrmEntityListenerMetadata
.getSorceId(jpaOrmEntityListenerMetadataId);
final String sourceMetadataKey = createProviderIdentifierKey(
sourceMetadataProvider, listenerJavaType, listenerPath);
final JpaOrmEntityListener sourceMetadata = (JpaOrmEntityListener) getMetadataService()
.get(sourceMetadataKey);
// Check source metadata
if (sourceMetadata == null || !sourceMetadata.isValid()) {
// Can't get the entityListener information, so we
// can't register it.
return null;
}
if (sourceMetadata.getEntityClass() == null) {
throw new IllegalArgumentException(
sourceMetadataKey
.concat(" doesn't provides the Entity class."));
}
if (sourceMetadata.getListenerClass() == null) {
throw new IllegalArgumentException(
sourceMetadataKey
.concat(" doesn't provides the Listener class."));
}
// Add entity-listener to orm.xml thru operations
getOperations().addEntityListener(sourceMetadata,
sourceMetadataProvider);
return new JpaOrmEntityListenerMetadata(jpaOrmEntityListenerMetadataId,
sourceMetadata);
}
public String getProvidesType() {
return JpaOrmEntityListenerMetadata.getMetadataIdentiferType();
}
public void notify(final String upstreamDependency,
String downstreamDependency) {
// Cleanup entity-listener of all entities
if (downstreamDependency == null) {
// Check if upstream s a Jpa ActiveRecord Metadata
if (JpaActiveRecordMetadata.isValid(upstreamDependency)) {
// Get entity
JavaType entity = JpaActiveRecordMetadata
.getJavaType(upstreamDependency);
// Call getOperations() to perform clean up
getOperations().cleanUpEntityListeners(entity);
}
}
if (MetadataIdentificationUtils
.isIdentifyingClass(downstreamDependency)) {
// A physical Java type has changed, and determine what the
// corresponding local metadata identification string would have
// been
// Gets provider registered
List<String> resiteredListeners = getRegistry().getListenerOrder();
boolean found = false;
// For every provider
for (String providerId : resiteredListeners) {
// Check if is a metadata from current provider
if (isMetadaFromProvider(providerId, upstreamDependency)) {
// Check if it' valid
String providerMetadataClass = getMetadaClass(providerId);
if (isMetadaValid(providerMetadataClass, upstreamDependency)) {
// Adjust downstream metadata
final JavaType javaType = getJavaType(
providerMetadataClass, upstreamDependency);
final LogicalPath path = getPath(providerMetadataClass,
upstreamDependency);
downstreamDependency = JpaOrmEntityListenerMetadata
.createIdentifier(javaType, path, providerId);
found = true;
}
// provider found: exit for
break;
}
}
if (!found) {
// nothing to do
return;
}
// We only need to proceed if the downstream dependency relationship
// is not already registered
// (if it's already registered, the event will be delivered directly
// later on)
if (getMetadataDependencyRegistry().getDownstream(
upstreamDependency).contains(downstreamDependency)) {
return;
}
// produces metadata
getMetadataService().evictAndGet(downstreamDependency);
}
}
/**
* Gets Logical path form a provider-metadata
*
* @param providerMetadataClass
* @param dependencyId
* @return
*/
private LogicalPath getPath(String providerMetadataClass,
String dependencyId) {
return PhysicalTypeIdentifierNamingUtils.getPath(providerMetadataClass,
dependencyId);
}
/**
* Gets JavaT7ype from a provider-metadata
*
* @param providerMetadataClass
* @param dependencyId
* @return
*/
private JavaType getJavaType(String providerMetadataClass,
String dependencyId) {
return PhysicalTypeIdentifierNamingUtils.getJavaType(
providerMetadataClass, dependencyId);
}
/**
* Gets metadata class from a provider-metadata-id
*
* @param providerId
* @return
*/
private String getMetadaClass(String providerId) {
return MetadataIdentificationUtils.getMetadataClass(providerId);
}
/**
* If metadata is from provider-metadata-id
*
* @param providerId
* @param idToCheck
* @return
*/
private boolean isMetadaFromProvider(String providerId, String idToCheck) {
return StringUtils.equals(getMetadaClass(providerId),
getMetadaClass(idToCheck));
}
/**
* If metadata is valid
*
* @param providerMetadataClass
* @param idToCheck
* @return
*/
private boolean isMetadaValid(String providerMetadataClass, String idToCheck) {
return PhysicalTypeIdentifierNamingUtils.isValid(providerMetadataClass,
idToCheck);
}
/**
* Create a metadata identification string for a provider metadata
*
* @param sourceMetadataProvider
* @param listenerJavaType
* @param listenerPath
* @return
*/
private String createProviderIdentifierKey(String sourceMetadataProvider,
JavaType listenerJavaType, LogicalPath listenerPath) {
return PhysicalTypeIdentifierNamingUtils.createIdentifier(
getMetadaClass(sourceMetadataProvider), listenerJavaType,
listenerPath);
}
public MetadataDependencyRegistry getMetadataDependencyRegistry() {
if (metadataDependencyRegistry == null) {
// Get all Services implement MetadataDependencyRegistry interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(
MetadataDependencyRegistry.class.getName(),
null);
for (ServiceReference<?> ref : references) {
return (MetadataDependencyRegistry) this.context
.getService(ref);
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load MetadataDependencyRegistry on JpaOrmEntityListenerMetadataListener.");
return null;
}
}
else {
return metadataDependencyRegistry;
}
}
public MetadataService getMetadataService() {
if (metadataService == null) {
// Get all Services implement MetadataService interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(
MetadataService.class.getName(), null);
for (ServiceReference<?> ref : references) {
return (MetadataService) this.context.getService(ref);
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load MetadataService on JpaOrmEntityListenerMetadataListener.");
return null;
}
}
else {
return metadataService;
}
}
public JpaOrmEntityListenerRegistry getRegistry() {
if (registry == null) {
// Get all Services JpaOrmEntityListenerRegistry MetadataService
// interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(
JpaOrmEntityListenerRegistry.class.getName(),
null);
for (ServiceReference<?> ref : references) {
return (JpaOrmEntityListenerRegistry) this.context
.getService(ref);
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load JpaOrmEntityListenerRegistry on JpaOrmEntityListenerMetadataListener.");
return null;
}
}
else {
return registry;
}
}
public JpaOrmEntityListenerOperations getOperations() {
if (operations == null) {
// Get all Services JpaOrmEntityListenerOperations MetadataService
// interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(
JpaOrmEntityListenerOperations.class.getName(),
null);
for (ServiceReference<?> ref : references) {
return (JpaOrmEntityListenerOperations) this.context
.getService(ref);
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load JpaOrmEntityListenerOperations on JpaOrmEntityListenerMetadataListener.");
return null;
}
}
else {
return operations;
}
}
}