/*
* 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.web.mvc.addon.jquery;
import java.util.logging.Logger;
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.web.mvc.controller.addon.finder.WebFinderMetadata;
import org.springframework.roo.addon.web.mvc.controller.addon.scaffold.WebScaffoldMetadata;
import org.springframework.roo.addon.web.mvc.jsp.JspMetadataListener;
import org.springframework.roo.metadata.DefaultMetadataService;
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.process.manager.FileManager;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.support.logging.HandlerUtils;
/**
* Listener that is invoked when implementation of {@link JQueryMetadata} or
* {@link WebFinderMetadata} (both acts as source meta-data) identification has
* requested to notify {@link JQueryJspMetadata} destination meta-data
* identification of an event.
* <p/>
* Provides the {@link JQueryJspMetadata}, that is, this class collects from
* OSGi services the needed info to create the {@link JQueryMetadata}.
* <p/>
* Both {@link MetadataProvider} and {@link MetadataNotificationListener}
* interfaces must be implemented together because {@link JQueryJspMetadata}
* depends on {@link JQueryMetadata} changes. In that case, we must notify both
* the {@code upstreamDependency} and the {@code downstreamDependency} to tell
* the listener the dependency is. To do that the
* {@link DefaultMetadataService#notify(String, String)} requires the
* {@link MetadataProvider} implements the {@link MetadataNotificationListener}
* too.
*
* @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>
* @since 1.1.0
*/
@Component
@Service
public class JQueryJspMetadataListener implements MetadataProvider,
MetadataNotificationListener {
protected final static Logger LOGGER = HandlerUtils
.getLogger(JQueryJspMetadataListener.class);
// ------------ OSGi component attributes ----------------
private BundleContext context;
private MetadataDependencyRegistry metadataDependencyRegistry;
private MetadataService metadataService;
private JQueryOperations operations;
private JspMetadataListener jspMetadataListener;
private FileManager fileManager;
/**
* Registers the dependency between upstream {@link JQueryMetadata},
* upstream {@link WebFinderMetadata} and this meta-data as downstream.
* <p/>
* Registers this listener to be invoked when implementation of
* {@link JQueryMetadata} or {@link WebFinderMetadata} (both acts as source
* meta-data) identification has requested to notify a particular
* destination meta-data identification of an event. Note this class listens
* for {@link JQueryJspMetadata} destination meta-data only.
*
* @param context
*/
protected void activate(final ComponentContext cContext) {
context = cContext.getBundleContext();
getMetadataDependencyRegistry().registerDependency(
JQueryMetadata.getMetadataIdentiferType(),
JQueryJspMetadata.getMetadataIdentiferType());
getMetadataDependencyRegistry().registerDependency(
WebFinderMetadata.getMetadataIdentiferType(),
JQueryJspMetadata.getMetadataIdentiferType());
getMetadataDependencyRegistry().registerDependency(
WebScaffoldMetadata.getMetadataIdentiferType(),
JQueryJspMetadata.getMetadataIdentiferType());
getMetadataDependencyRegistry().addNotificationListener(this);
}
/**
* Removes the dependencies with {@link JQueryMetadata} and
* {@link WebFinderMetadata}.
* <p/>
* De-register this instance to receive MetadataNotificationListener events.
*
* @param context
*/
protected void deactivate(final ComponentContext context) {
getMetadataDependencyRegistry().deregisterDependency(
JQueryMetadata.getMetadataIdentiferType(),
JQueryJspMetadata.getMetadataIdentiferType());
getMetadataDependencyRegistry().deregisterDependency(
WebFinderMetadata.getMetadataIdentiferType(),
JQueryJspMetadata.getMetadataIdentiferType());
getMetadataDependencyRegistry().deregisterDependency(
WebScaffoldMetadata.getMetadataIdentiferType(),
JQueryJspMetadata.getMetadataIdentiferType());
getMetadataDependencyRegistry().removeNotificationListener(this);
}
/**
* {@inheritDoc}
* <p/>
* Updates the view related to the Controller specified in the given
* meta-data identification string.
* <p/>
* Note the meta-data item neither contains nor composes details of the
* related Java type because it doesn't create any ITD.
*/
public MetadataItem get(final String jqueryJspMetadataId) {
// Get the Java type (Controller) that given meta-data ID refers to
final JavaType controller = JQueryJspMetadata
.getJavaType(jqueryJspMetadataId);
// Create a JQueryMetadata ID for same Java type than the Java type
// included in jqueryJspMetadataId
final String jqueryMetadataKey = JQueryMetadata.createIdentifier(
controller, JQueryJspMetadata.getPath(jqueryJspMetadataId));
// Get the meta-data means the given Java type has the specified
// meta-data, otherwise the ID was valid but the metadata is
// not currently available
final JQueryMetadata jqueryMetadata = (JQueryMetadata) getMetadataService()
.get(jqueryMetadataKey);
// If we created a valid JQueryMetada, given meta-data ID refers to
// JQueryMetadata and we must update related artifacts
if (jqueryMetadata != null && jqueryMetadata.isValid()) {
// Call to operations for update pages
getOperations().updateCrudJsp(controller, jqueryMetadata);
}
// JQueryMetadata is required, that is, if given Java type hasn't
// it there is nothing to do, neither in CRUD jspx nor finder jspx
else {
return null;
}
// Create a WebFinderMetadata ID for same Java type than the Java type
// included in jqueryJspMetadataId
final String finderMetadataKey = WebFinderMetadata.createIdentifier(
controller, JQueryJspMetadata.getPath(jqueryJspMetadataId));
// Get the meta-data means the given Java type has the specified
// meta-data, otherwise the ID was valid but the metadata is
// not currently available
final WebFinderMetadata finderMetadata = (WebFinderMetadata) getMetadataService()
.get(finderMetadataKey);
// Moreover, if we created a valid WebFinderMetadata, given meta-data
// ID refers to WebFinderMetadata and we must update the finders
if (finderMetadata != null) {
if (finderMetadata.isValid()) {
// Write pending changes to ensure that jsp file actually exists
getFileManager().commit();
// Call to operations for update pages
getOperations().updateFindJsp(controller, finderMetadata);
}
else {
// Finder meta-data is not valid
return null;
}
}
return new JQueryJspMetadata(jqueryJspMetadataId, jqueryMetadata);
}
public String getProvidesType() {
return JQueryJspMetadata.getMetadataIdentiferType();
}
public void notify(final String upstreamDependency,
String downstreamDependency) {
// Force JspMetadataListener
getJspMetadataListener().notify(upstreamDependency,
downstreamDependency);
if (MetadataIdentificationUtils
.isIdentifyingClass(downstreamDependency)) {
// If source meta-data identification (requester/notifier) is
// JQueryMetadata
if (JQueryMetadata.isValid(upstreamDependency)) {
final JavaType controller = JQueryMetadata
.getJavaType(upstreamDependency);
final LogicalPath path = JQueryMetadata
.getPath(upstreamDependency);
// Create the target meta-data identification that will
// receive the notification
downstreamDependency = JQueryJspMetadata.createIdentifier(
controller, path);
}
// If source meta-data identification (requester/notifier) is
// WebFinderMetadata
else if (WebFinderMetadata.isValid(upstreamDependency)) {
final JavaType controller = WebFinderMetadata
.getJavaType(upstreamDependency);
final LogicalPath path = WebFinderMetadata
.getPath(upstreamDependency);
downstreamDependency = JQueryJspMetadata.createIdentifier(
controller, path);
}
// If source meta-data identification (requester/notifier) is
// WebScaffoldMetadata
else if (WebScaffoldMetadata.isValid(upstreamDependency)) {
final JavaType controller = WebScaffoldMetadata
.getJavaType(upstreamDependency);
final LogicalPath path = WebScaffoldMetadata
.getPath(upstreamDependency);
downstreamDependency = JQueryJspMetadata.createIdentifier(
controller, path);
}
else {
// dependency not handled: 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;
}
// Notify to target meta-data identification, simply call
// of the meta-data Provider. In this case the downstream is
// JQueryJspMetadata then
// {@link JQueryJspMetadataListener#get(String)} will be called
// Note that evictAndGet method register downstreamDependency below
// related to current upstreamDependency automatically, so next
// method executions the if condition above will be true
getMetadataService().evictAndGet(downstreamDependency);
}
}
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 JQueryJspMetadataListener.");
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 JQueryJspMetadataListener.");
return null;
}
}
else {
return metadataService;
}
}
public JQueryOperations getOperations() {
if (operations == null) {
// Get all Services implement JQueryOperations interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(
JQueryOperations.class.getName(), null);
for (ServiceReference<?> ref : references) {
return (JQueryOperations) this.context.getService(ref);
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load JQueryOperations on JQueryJspMetadataListener.");
return null;
}
}
else {
return operations;
}
}
public JspMetadataListener getJspMetadataListener() {
if (jspMetadataListener == null) {
// Get all Services implement MetadataNotificationListener interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(
MetadataNotificationListener.class.getName(),
null);
for (ServiceReference<?> ref : references) {
MetadataNotificationListener listener = (MetadataNotificationListener) this.context
.getService(ref);
if (listener.getClass().equals(JspMetadataListener.class)) {
jspMetadataListener = (JspMetadataListener) listener;
return jspMetadataListener;
}
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load JspMetadataListener on JQueryJspMetadataListener.");
return null;
}
}
else {
return jspMetadataListener;
}
}
public FileManager getFileManager() {
if (fileManager == null) {
// Get all Services implement JQueryOperations interface
try {
ServiceReference<?>[] references = this.context
.getAllServiceReferences(FileManager.class.getName(),
null);
for (ServiceReference<?> ref : references) {
return (FileManager) this.context.getService(ref);
}
return null;
}
catch (InvalidSyntaxException e) {
LOGGER.warning("Cannot load FileManager on JQueryJspMetadataListener.");
return null;
}
}
else {
return fileManager;
}
}
}