package org.gcube.portlets.widgets.mpformbuilder.server; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import javax.xml.bind.JAXBException; import org.gcube.common.metadataprofilediscovery.MetadataProfileReader; import org.gcube.common.metadataprofilediscovery.bean.MetadataProfile; import org.gcube.common.metadataprofilediscovery.jaxb.MetadataField; import org.gcube.common.metadataprofilediscovery.jaxb.MetadataFormat; import org.gcube.common.metadataprofilediscovery.jaxb.MetadataGrouping; import org.gcube.common.metadataprofilediscovery.jaxb.MetadataTagging; import org.gcube.common.metadataprofilediscovery.jaxb.MetadataValidator; import org.gcube.common.metadataprofilediscovery.jaxb.MetadataVocabulary; import org.gcube.common.metadataprofilediscovery.jaxb.NamespaceCategory; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.portlets.widgets.mpformbuilder.server.util.WsUtil; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.CategoryWrapper; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.DataTypeWrapper; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.FieldAsGroup; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.FieldAsTag; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileBean; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetadataFieldWrapper; import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.TaggingGroupingValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The Class MetadataDiscovery. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * * Sep 30, 2020 */ public class MetadataDiscovery { private static final Logger LOG = LoggerFactory.getLogger(MetadataDiscovery.class); /** * Gets the profiles names. * * @param scope the scope * @param genericResourceSecondaryType the generic resource secondary type in * which discover "gCube Metadata Profiles" * @return the profiles names * @throws Exception the exception */ public static List getProfilesNames(String scope, String genericResourceSecondaryType) throws Exception { String currentContext = ScopeProvider.instance.get(); try { ScopeProvider.instance.set(scope); List toReturn = new ArrayList(); MetadataProfileReader reader = new MetadataProfileReader(genericResourceSecondaryType); List listProfiles = reader.getListOfMetadataProfiles(); if (listProfiles != null && !listProfiles.isEmpty()) { for (MetadataProfile profile : listProfiles) { toReturn.add(profile.getName()); } } return toReturn; } catch (Exception e) { LOG.error("Failed to fetch profiles", e); } finally { ScopeProvider.instance.set(currentContext); } return null; } /** * Gets the metadata profiles list. * * @param scope the scope * @param gRSecondaryType the g R secondary type * @param resourceName the resource name * @return the metadata profiles list * @throws Exception the exception */ public static List getMetadataProfilesList(String scope, String gRSecondaryType, String resourceName) throws Exception { List beans = new ArrayList(); LOG.debug("Discovering into scope " + scope); String currentContext = ScopeProvider.instance.get(); try { ScopeProvider.instance.set(scope); // TODO two reset methods could be added to force the reader to read again these // information (after a while) MetadataProfileReader reader = new MetadataProfileReader(gRSecondaryType, resourceName); List profiles = reader.getListOfMetadataProfiles(); prettyPrintProfiles(profiles); LOG.info("Profiles are " + profiles.size()); List categories = reader.getListOfNamespaceCategories(); if (categories == null) categories = new ArrayList(); LOG.debug("All Categories are " + categories); for (MetadataProfile profile : profiles) { LOG.debug("Wrapping profile with name " + profile.getName() + " and type " + profile.getMetadataType()); MetadataFormat metadata = reader.getMetadataFormatForMetadataProfile(profile); MetaDataProfileBean bean = toMetaDataProfileBean(metadata, categories, profile.getName()); beans.add(bean); if(!WsUtil.isWithinPortal()) { LOG.info("DEV MODE ENABLED - Out of portal!"); randomizeCurrentValues(bean.getMetadataFields()); } } prettyPrintList(beans); LOG.info("Returning " + beans.size() + " profile/s"); } catch (Exception e) { LOG.error("Error while retrieving metadata beans ", e); throw new Exception("Failed to parse Types: " + e.getMessage()); } finally { ScopeProvider.instance.set(currentContext); } return beans; } private static void randomizeCurrentValues(List listFields) { LOG.info("DEV MODE ENABLED - Generationg random current value"); for (MetadataFieldWrapper metadataFieldWrapper : listFields) { DataTypeWrapper dtw = metadataFieldWrapper.getType(); switch (dtw) { case Boolean: metadataFieldWrapper.setCurrentValue(Boolean.FALSE.toString()); break; case Number: metadataFieldWrapper.setCurrentValue(new Random().nextInt()+""); break; case String: case Text: metadataFieldWrapper.setCurrentValue("Text "+UUID.randomUUID()); break; default: break; } } } /** * Gets the metadata profiles list. * * @param scope the scope * @param gRSecondaryType the g R secondary type * @return the metadata profiles list * @throws Exception the exception */ public static List getMetadataProfilesList(String scope, String gRSecondaryType) throws Exception { List beans = new ArrayList(); LOG.debug("Discovering into scope " + scope); String currentContext = ScopeProvider.instance.get(); try { ScopeProvider.instance.set(scope); // TODO two reset methods could be added to force the reader to read again these // information (after a while) MetadataProfileReader reader = new MetadataProfileReader(gRSecondaryType); List profiles = reader.getListOfMetadataProfiles(); prettyPrintProfiles(profiles); LOG.info("Profiles are " + profiles.size()); List categories = reader.getListOfNamespaceCategories(); if (categories == null) categories = new ArrayList(); LOG.debug("All Categories are " + categories); for (MetadataProfile profile : profiles) { LOG.debug("Wrapping profile with name " + profile.getName() + " and type " + profile.getMetadataType()); MetadataFormat metadata = reader.getMetadataFormatForMetadataProfile(profile); MetaDataProfileBean bean = toMetaDataProfileBean(metadata, categories, profile.getName()); beans.add(bean); } prettyPrintList(beans); LOG.info("Returning " + beans.size() + " profile/s"); } catch (Exception e) { LOG.error("Error while retrieving metadata beans ", e); throw new Exception("Failed to parse Types: " + e.getMessage()); } finally { ScopeProvider.instance.set(currentContext); } return beans; } private static void prettyPrintProfiles(List profiles) { if(LOG.isDebugEnabled() && profiles!=null) { LOG.debug("Pretty print list of profiles: "); for (MetadataProfile profile : profiles) { LOG.debug(profile.toString()); } } } private static void prettyPrintList(List beans) { if(LOG.isDebugEnabled() && beans!=null) { LOG.debug("Pretty print list of beans: "); for (MetaDataProfileBean metaDataProfileBean : beans) { LOG.debug(metaDataProfileBean.toString()); } } } /** * Gets the metadata profile. * * @param metadataProfileStream the metadata profile stream * @return the metadata profile * @throws JAXBException the JAXB exception */ public static MetaDataProfileBean getMetadataProfile(InputStream metadataProfileStream) throws JAXBException { MetadataFormat metadata = MetadataProfileReader.toMetadataFormat(metadataProfileStream); return toMetaDataProfileBean(metadata, null, null); } /** * To meta data profile bean. * * @param metadata the metadata * @param categories the categories * @param profileName the profile name * @return the meta data profile bean */ private static MetaDataProfileBean toMetaDataProfileBean(MetadataFormat metadata, List categories, String profileName){ String type = metadata.getType(); String title = profileName!=null?profileName:type; List fields = metadata.getMetadataFields(); // we need to wrap the list of metadata and categories List fieldsWrapper = new ArrayList( fields != null ? fields.size() : 0); List categoriesWrapper = new ArrayList(categories.size()); Map idToCategory = new HashMap(categories.size()); // manage the categories for (NamespaceCategory category : categories) { CategoryWrapper categoryWrapped = new CategoryWrapper(category.getId(), category.getTitle(), category.getDescription()); categoriesWrapper.add(categoryWrapped); idToCategory.put(category.getId(), categoryWrapped); } // also evaluate the fields for each category Map> fieldsPerCategory = new HashMap>( categoriesWrapper.size()); // manage the fields if (fields != null) for (MetadataField metadataField : fields) { MetadataFieldWrapper wrapperObj = new MetadataFieldWrapper(); wrapperObj.setFieldNameFromCategory(metadataField.getCategoryFieldQName()); try { wrapperObj.setType(DataTypeWrapper.valueOf(metadataField.getDataType().toString())); }catch (Exception e) { // TODO: handle exception LOG.warn("No valueOf to DataTypeWrapper for value "+metadataField.getDataType().toString() +", using default String"); wrapperObj.setType(DataTypeWrapper.String); } wrapperObj.setDefaultValue(metadataField.getDefaultValue()); wrapperObj.setFieldName(metadataField.getFieldName()); wrapperObj.setMandatory(metadataField.getMandatory()); wrapperObj.setNote(metadataField.getNote()); MetadataValidator validator = metadataField.getValidator(); LOG.debug(metadataField.getFieldName() +" validator is: "+validator); if (validator != null) wrapperObj.setValidator(validator.getRegularExpression()); MetadataVocabulary vocabulary = metadataField.getVocabulary(); if (vocabulary != null) { wrapperObj.setVocabulary(vocabulary.getVocabularyFields()); wrapperObj.setMultiSelection(vocabulary.isMultiSelection()); } MetadataTagging tagging = metadataField.getTagging(); if (tagging != null) { FieldAsTag tag = new FieldAsTag(); tag.setCreate(tagging.getCreate()); tag.setSeparator(tagging.getSeparator()); tag.setTaggingValue(TaggingGroupingValue.valueOf(tagging.getTaggingValue().toString())); wrapperObj.setAsTag(tag); } MetadataGrouping grouping = metadataField.getGrouping(); if (grouping != null) { FieldAsGroup group = new FieldAsGroup(); group.setCreate(grouping.getCreate()); group.setPropagateUp(grouping.getPropagateUp()); group.setGroupingValue( TaggingGroupingValue.valueOf(grouping.getGroupingValue().toString())); wrapperObj.setAsGroup(group); } // set to which category this field belongs to and vice-versa if (metadataField.getCategoryRef() != null) { CategoryWrapper ownerCategory = idToCategory.get(metadataField.getCategoryRef()); if (ownerCategory == null) { LOG.warn("A field with categoryref " + metadataField.getCategoryRef() + " has been found, but" + " such category is not defined within the namespaces"); } else { wrapperObj.setOwnerCategory(ownerCategory); List fieldsPerCategoryN = fieldsPerCategory .get(metadataField.getCategoryRef()); if (fieldsPerCategoryN == null) fieldsPerCategoryN = new ArrayList(); fieldsPerCategoryN.add(wrapperObj); fieldsPerCategory.put(metadataField.getCategoryRef(), fieldsPerCategoryN); // instead of re-looping on the fieldsPerCategory map later, just set this // potentially partial list ownerCategory.setFieldsForThisCategory(fieldsPerCategoryN); } } // Added by Francesco int maxOccurs = 1; // Default value is 1. A field should occur once. if (metadataField.getMaxOccurs() != null) { try { // the field can appear an unlimited number of times. if (metadataField.getMaxOccurs().equals("*")) { maxOccurs = Integer.MAX_VALUE; } else { // the field must appear N times; maxOccurs = Integer.parseInt(metadataField.getMaxOccurs()); } } catch (Exception e) { // silent } wrapperObj.setMaxOccurs(maxOccurs); } fieldsWrapper.add(wrapperObj); } // filter the categories without children here Iterator categoryToRemoveIT = categoriesWrapper.iterator(); while (categoryToRemoveIT.hasNext()) { CategoryWrapper categoryWrapper = (CategoryWrapper) categoryToRemoveIT.next(); if (categoryWrapper.getFieldsForThisCategory() == null) categoryToRemoveIT.remove(); } return new MetaDataProfileBean(type, title, fieldsWrapper, categoriesWrapper); } }