/* * 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.web.report.roo.addon.addon; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Logger; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.gvnix.web.report.roo.addon.annotations.GvNIXReports; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.springframework.roo.addon.propfiles.PropFileOperations; import org.springframework.roo.addon.web.mvc.controller.addon.details.WebMetadataService; import org.springframework.roo.addon.web.mvc.controller.addon.scaffold.WebScaffoldMetadata; import org.springframework.roo.addon.web.mvc.controller.addon.scaffold.WebScaffoldMetadataProvider; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.TypeLocationService; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.MemberFindingUtils; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.details.annotations.ArrayAttributeValue; import org.springframework.roo.classpath.details.annotations.StringAttributeValue; import org.springframework.roo.classpath.itd.AbstractItdMetadataProvider; import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.classpath.scanner.MemberDetails; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.support.logging.HandlerUtils; /** * Provides {@link ReportMetadata}. This type is called by Roo to retrieve the * metadata for this add-on. Use this type to reference external types and * services needed by the metadata type. Register metadata triggers and * dependencies here. Also define the unique add-on ITD identifier. * * @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 */ @Component @Service public final class ReportMetadataProvider extends AbstractItdMetadataProvider { private static final Logger logger = HandlerUtils .getLogger(ReportMetadataProvider.class); protected TypeLocationService typeLocationService; protected WebScaffoldMetadataProvider webScaffoldMetadataProvider; protected ProjectOperations projectOperations; protected PropFileOperations propFileOperations; protected WebMetadataService webMetadataService; protected ReportConfigService reportConfigService; /** * The activate method for this OSGi component, this will be called by the * OSGi container upon bundle activation (result of the 'addon install' * command) * * @param context the component context can be used to get access to the * OSGi container (ie find out if certain bundles are active) */ protected void activate(ComponentContext cContext) { context = cContext.getBundleContext(); getMetadataDependencyRegistry().registerDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); getWebScaffoldMetadataProvider().addMetadataTrigger( new JavaType(GvNIXReports.class.getName())); addMetadataTrigger(new JavaType(GvNIXReports.class.getName())); } /** * The deactivate method for this OSGi component, this will be called by the * OSGi container upon bundle deactivation (result of the 'addon uninstall' * command) * * @param context the component context can be used to get access to the * OSGi container (ie find out if certain bundles are active) */ protected void deactivate(ComponentContext context) { getMetadataDependencyRegistry().deregisterDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); getWebScaffoldMetadataProvider().removeMetadataTrigger( new JavaType(GvNIXReports.class.getName())); removeMetadataTrigger(new JavaType(GvNIXReports.class.getName())); } /** * Return an instance of the Metadata offered by this add-on */ @Override protected ItdTypeDetailsProvidingMetadataItem getMetadata( String metadataIdentificationString, JavaType aspectName, PhysicalTypeMetadata governorPhysicalTypeMetadata, String itdFilename) { // Setup JasperReports support getReportConfigService().setup(); JavaType javaType = ReportMetadata .getJavaType(metadataIdentificationString); // We know governor type details are non-null and can be safely cast ClassOrInterfaceTypeDetails controllerCoID = (ClassOrInterfaceTypeDetails) governorPhysicalTypeMetadata .getMemberHoldingTypeDetails(); Validate.notNull( controllerCoID, "Governor failed to provide class type details, in violation of superclass contract"); MemberDetails controllerMemberDetails = getMemberDetailsScanner() .getMemberDetails(getClass().getName(), controllerCoID); List<StringAttributeValue> definedReports = new ArrayList<StringAttributeValue>(); AnnotationMetadata gvNixReportsAnnotation = MemberFindingUtils .getAnnotationOfType(controllerCoID.getAnnotations(), new JavaType(GvNIXReports.class.getName())); if (gvNixReportsAnnotation != null) { AnnotationAttributeValue<?> val = gvNixReportsAnnotation .getAttribute(new JavaSymbolName("value")); if (val != null) { // Ensure we have an array of strings if (!(val instanceof ArrayAttributeValue<?>)) { // logger.warning(getErrorMsg()); return null; } ArrayAttributeValue<?> arrayVal = (ArrayAttributeValue<?>) val; Map<String, String> validReportNameFormats = getValidReportNameFormats(arrayVal); /* * Dealing with reportNames defined several times in the gvNIX * annotation. With the validReportNameFormats HashMap we can * know if a report is defined more than once and handle it as * just one definition aggregating the formats defined in each * report definition. TODO: would be a great improvement to * advise user about duplicity of report definitions */ for (Entry<String, String> reportEntry : validReportNameFormats .entrySet()) { String reportName = reportEntry.getKey().toLowerCase(); StringAttributeValue newSV = new StringAttributeValue( new JavaSymbolName("ignored"), reportName.concat( "|").concat( validReportNameFormats.get(reportName))); definedReports.add(newSV); } } } LogicalPath path = ReportMetadata.getPath(metadataIdentificationString); String webScaffoldMetadataKey = WebScaffoldMetadata.createIdentifier( javaType, path); getMetadataDependencyRegistry().registerDependency( webScaffoldMetadataKey, metadataIdentificationString); WebScaffoldMetadata webScaffoldMetadata = (WebScaffoldMetadata) getWebScaffoldMetadataProvider() .get(webScaffoldMetadataKey); if (webScaffoldMetadata == null) { logger.warning("The report can not be created over a Controlloer without " + "@RooWebScaffold annotation and its 'fromBackingObject' attribute " + "set. Check " + javaType.getFullyQualifiedTypeName()); return null; } // Pass dependencies required by the metadata in through its constructor return new ReportMetadata(metadataIdentificationString, aspectName, governorPhysicalTypeMetadata, controllerMemberDetails.getMethods(), getMetadataService(), getMemberDetailsScanner(), getMetadataDependencyRegistry(), webScaffoldMetadata, getWebMetadataService(), getFileManager(), getProjectOperations(), getPropFileOperations(), definedReports); } /** * Returns a HashMap<String, String>. Key is reportName; Value is the csv of * formats. * * @param arrayVal * @return */ private Map<String, String> getValidReportNameFormats( ArrayAttributeValue<?> arrayVal) { HashMap<String, String> validReportNameFormats = new HashMap<String, String>(); StringAttributeValue sAttrValue = null; String[] reportNameFormat; for (Object o : arrayVal.getValue()) { if (!(o instanceof StringAttributeValue)) { return null; } sAttrValue = (StringAttributeValue) o; reportNameFormat = ReportMetadata.stripGvNixReportValue(sAttrValue .getValue()); if (ReportMetadata.isValidFormat(reportNameFormat[1])) { if (validReportNameFormats.containsKey(reportNameFormat[0])) { // logger.warning("A report with the name ** " + // reportNameFormat[0] + // " ** is already defined. Please check it"); validReportNameFormats.put(reportNameFormat[0], ReportMetadata.updateFormat(validReportNameFormats .get(reportNameFormat[0]), reportNameFormat[1])); } else { validReportNameFormats.put(reportNameFormat[0], reportNameFormat[1]); } } } return validReportNameFormats; } /** * Define the unique ITD file name extension, here the resulting file name * will be **_ROO_GvNixReport.aj */ public String getItdUniquenessFilenameSuffix() { return "GvNIXReport"; } @Override protected String getGovernorPhysicalTypeIdentifier( String metadataIdentificationString) { JavaType javaType = ReportMetadata .getJavaType(metadataIdentificationString); LogicalPath path = ReportMetadata.getPath(metadataIdentificationString); return PhysicalTypeIdentifier.createIdentifier(javaType, path); } @Override protected String createLocalIdentifier(JavaType javaType, LogicalPath path) { return ReportMetadata.createIdentifier(javaType, path); } public String getProvidesType() { return ReportMetadata.getMetadataIdentiferType(); } public WebScaffoldMetadataProvider getWebScaffoldMetadataProvider() { if (webScaffoldMetadataProvider == null) { // Get all Services implement WebScaffoldMetadataProvider interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( WebScaffoldMetadataProvider.class.getName(), null); for (ServiceReference<?> ref : references) { return (WebScaffoldMetadataProvider) this.context .getService(ref); } return null; } catch (InvalidSyntaxException e) { logger.warning("Cannot load WebScaffoldMetadataProvider on ReportMetadataProvider."); return null; } } else { return webScaffoldMetadataProvider; } } public ProjectOperations getProjectOperations() { if (projectOperations == null) { // Get all Services implement ProjectOperations interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( ProjectOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (ProjectOperations) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { logger.warning("Cannot load ProjectOperations on ReportMetadataProvider."); return null; } } else { return projectOperations; } } public PropFileOperations getPropFileOperations() { if (propFileOperations == null) { // Get all Services implement PropFileOperations interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( PropFileOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (PropFileOperations) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { logger.warning("Cannot load PropFileOperations on ReportMetadataProvider."); return null; } } else { return propFileOperations; } } public WebMetadataService getWebMetadataService() { if (webMetadataService == null) { // Get all Services implement WebMetadataService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( WebMetadataService.class.getName(), null); for (ServiceReference<?> ref : references) { return (WebMetadataService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { logger.warning("Cannot load WebMetadataService on ReportMetadataProvider."); return null; } } else { return webMetadataService; } } public ReportConfigService getReportConfigService() { if (reportConfigService == null) { // Get all Services implement ReportConfigService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( ReportConfigService.class.getName(), null); for (ServiceReference<?> ref : references) { return (ReportConfigService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { logger.warning("Cannot load ReportConfigService on ReportMetadataProvider."); return null; } } else { return reportConfigService; } } }