diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 91347d1..59a42fb 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,7 @@ - + + + @@ -48,7 +50,9 @@ - + + + @@ -97,7 +101,9 @@ - + + + @@ -146,7 +152,9 @@ - + + + @@ -195,11 +203,15 @@ + + uses - + + + @@ -248,7 +260,9 @@ - + + + @@ -297,7 +311,9 @@ - + + + @@ -346,7 +362,9 @@ - + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index fc9dbe7..6cc96c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - [#22685] Migrated to geoportal-data-list configuration for UCD - [#23784] Migrated list and reload, searching and ordering functionalities - [#23785] Migrated the GNA functionalities -- [#23834] Create Relation facility +- [#23834] Create Relationship facility - [#23913] Integrated with GUI presentation configurations read from IS - Moved to maven-portal-bom v3.7.0[-SNAPSHOT] diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalClientCaches.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalClientCaches.java index e00bdc3..194df51 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalClientCaches.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalClientCaches.java @@ -9,6 +9,7 @@ import java.util.TreeMap; import org.gcube.application.geoportalcommon.shared.geoportal.ConfigurationDV; import org.gcube.application.geoportalcommon.shared.geoportal.config.ItemFieldDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.UseCaseDescriptorDV; import org.gcube.portlets.user.geoportaldataentry.client.ui.card.GeoNaFormCardModel; @@ -31,7 +32,7 @@ public class GeoPortalClientCaches { private Map mapSearchingFilterParametersForProfileId; - private Map> mapRelationsNamesForProfileId; + private Map> mapRelationsNamesForProfileId; /** * Instantiates a new geo portal client caches. @@ -41,7 +42,7 @@ public class GeoPortalClientCaches { mapHandlersConfigurationsForProfileId = new HashMap>>(); mapSearchingFilterParametersForProfileId = new HashMap(); mapUseCaseDescriptor = new HashMap(); - mapRelationsNamesForProfileId = new HashMap>(); + mapRelationsNamesForProfileId = new HashMap>(); } /** @@ -55,22 +56,23 @@ public class GeoPortalClientCaches { } /** - * Put list relation names for profile ID. + * Put list relationships definition for profile ID. * - * @param profileId the profile id - * @param listRealationNames the list realation names + * @param profileId the profile id + * @param relationshipDef the relationship def */ - public void putListRelationNamesForProfileID(String profileId, List listRealationNames) { - mapRelationsNamesForProfileId.put(profileId, listRealationNames); + public void putListRelationshipsDefinitionForProfileID(String profileId, + List relationshipDef) { + mapRelationsNamesForProfileId.put(profileId, relationshipDef); } /** - * Gets the list relation names for profile id. + * Gets the list relationship definition for profile id. * * @param profileId the profile id - * @return the list relation names for profile id + * @return the list relationship definition for profile id */ - public List getListRelationNamesForProfileId(String profileId) { + public List getListRelationshipDefinitionForProfileId(String profileId) { return mapRelationsNamesForProfileId.get(profileId); } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java index 426190a..bdc6bf0 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java @@ -22,6 +22,7 @@ import org.gcube.application.geoportalcommon.shared.geoportal.project.LifecycleI import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.RelationshipDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.HandlerDeclarationDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.UseCaseDescriptorDV; import org.gcube.portlets.user.geoportaldataentry.client.ConstantsGeoPortalDataEntryApp.ACTION_PERFORMED_ON_ITEM; import org.gcube.portlets.user.geoportaldataentry.client.GeoPortalClientCaches.CacheSearchingFilterParametersFromConfig; @@ -782,20 +783,20 @@ public class GeoPortalDataEntryApp implements EntryPoint { mainTabPanel.setFilteringParameters(seachingFilterParameters); searchingFilter = mainTabPanel.getCurrentProjectsSearchingFilter(); - // Searching in the cache if the list of relation names is present - List listRelationNames = geoportalCaches.getListRelationNamesForProfileId(profileID); - // Loading list of Relation Names for ProfileID - if (listRelationNames == null || listRelationNames.isEmpty()) { + // Searching in the cache if the list of relationship definition is present + List listRelationshipsDef = geoportalCaches.getListRelationshipDefinitionForProfileId(profileID); + // Loading list of relationships definition ProfileID + if (listRelationshipsDef == null || listRelationshipsDef.isEmpty()) { - GeoPortalDataEntryApp.geoportalDataEntryService.getRelationshipNames(profileID, - new AsyncCallback>() { + GeoPortalDataEntryApp.geoportalDataEntryService.getRelationshipsDefinition(profileID, + new AsyncCallback>() { @Override - public void onSuccess(List relationshipNames) { - GWT.log("getRelationshipNames for " + profileID + " are: " + relationshipNames); - geoportalCaches.putListRelationNamesForProfileID(profileID, relationshipNames); + public void onSuccess(List relationshipDef) { + GWT.log("getRelationshipNames for " + profileID + " are: " + relationshipDef); + geoportalCaches.putListRelationshipsDefinitionForProfileID(profileID, relationshipDef); mainTabPanel.enableRelatioshipFacilities( - relationshipNames != null && !relationshipNames.isEmpty()); + relationshipDef != null && !relationshipDef.isEmpty()); } @Override @@ -848,19 +849,19 @@ public class GeoPortalDataEntryApp implements EntryPoint { modal.setTitle("Creating relation..."); modal.setWidth(800); modal.setCloseVisible(false); - String relName = createRelationHE.getRelationshipName(); + final RelationshipDefinitionDV relationSelected = createRelationHE.getRelationSelected(); String fromProfileID = createRelationHE.getFromProject().getProfileID(); String fromProjectID = createRelationHE.getFromProject().getId(); String toProfileID = createRelationHE.getToProject().getProfileID(); String toProjectID = createRelationHE.getToProject().getId(); final VerticalPanel modalContainerPanel = new VerticalPanel(); - final LoaderIcon loader = new LoaderIcon("Trying to create the relation " + relName + final LoaderIcon loader = new LoaderIcon("Trying to create the relation " + relationSelected.getLabel() + " from Project ID: " + fromProjectID + " to Project ID: " + toProjectID); modalContainerPanel.add(loader); modal.add(modalContainerPanel); - + GeoportalDataEntryServiceAsync.Util.getInstance().createRelationship(fromProfileID, fromProjectID, - relName, toProfileID, toProjectID, new AsyncCallback() { + relationSelected.getId(), toProfileID, toProjectID, new AsyncCallback() { @Override public void onFailure(Throwable caught) { @@ -878,7 +879,7 @@ public class GeoPortalDataEntryApp implements EntryPoint { } @Override - public void onSuccess(RelationshipDV result) { + public void onSuccess(Void result) { modal.setTitle("Relationship created"); modalContainerPanel.clear(); modal.setCloseVisible(true); @@ -890,7 +891,7 @@ public class GeoPortalDataEntryApp implements EntryPoint { Alert alert = new Alert(); alert.setType(AlertType.SUCCESS); alert.setClose(false); - alert.setText("Relationship " + relName + " created correctly!"); + alert.setText("Relationship " + relationSelected.getLabel() + " created correctly!"); modal.add(alert); String htmlMsg = "In the project with:"; @@ -901,13 +902,13 @@ public class GeoPortalDataEntryApp implements EntryPoint { + ": " + createRelationHE.getFromProject().getFirstEntryOfMap().getValue() + ""; htmlMsg += ""; - htmlMsg += "has been created the relationship " + relName + htmlMsg += "has been created the relationship " + relationSelected.getLabel() + " to the project wiht id: " + toProjectID; modal.add(new HTML(htmlMsg)); - ReportTemplateToHTML rtth = new ReportTemplateToHTML("Relationship", result.getAsJSON(), - false, false); - rtth.showAsJSON(false); - modal.add(rtth); +// ReportTemplateToHTML rtth = new ReportTemplateToHTML("Relationship", result.getAsJSON(), +// false, false); +// rtth.showAsJSON(false); +// modal.add(rtth); appManagerBus.fireEvent(new CloseCreateRelationGUIEvent()); } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java index 56655fb..87f547f 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryService.java @@ -10,6 +10,7 @@ import org.gcube.application.geoportalcommon.shared.geoportal.config.ActionDefin import org.gcube.application.geoportalcommon.shared.geoportal.project.LifecycleInformationDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.RelationshipDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.UseCaseDescriptorDV; import org.gcube.application.geoportalcommon.shared.products.ConcessioneDV; import org.gcube.application.geoportalcommon.shared.products.content.WorkspaceContentDV; @@ -168,27 +169,26 @@ public interface GeoportalDataEntryService extends RemoteService { ProjectDV performActionSteps(String profileID, String projectID, ActionDefinitionDV action) throws Exception; /** - * Perform action steps. + * Gets the relationships definition. * * @param profileID the profile ID - * @return the project DV + * @return the relationships definition * @throws Exception the exception */ - List getRelationshipNames(String profileID) throws Exception; + List getRelationshipsDefinition(String profileID) throws Exception; /** * Creates the relationship. * - * @param fromProfileID the from profile ID - * @param fromProjectID the from project ID - * @param relationshipName the relationship name - * @param toProfileID the to profile ID - * @param toProjectID the to project ID - * @return the relationship DV + * @param fromProfileID the from profile ID + * @param fromProjectID the from project ID + * @param relationshipID the relationship ID + * @param toProfileID the to profile ID + * @param toProjectID the to project ID * @throws Exception the exception */ - RelationshipDV createRelationship(String fromProfileID, String fromProjectID, String relationshipName, - String toProfileID, String toProjectID) throws Exception; + void createRelationship(String fromProfileID, String fromProjectID, String relationshipID, String toProfileID, + String toProjectID) throws Exception; /** * Gets the project by ID. diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java index de333be..6b02c3c 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoportalDataEntryServiceAsync.java @@ -10,6 +10,7 @@ import org.gcube.application.geoportalcommon.shared.geoportal.config.ActionDefin import org.gcube.application.geoportalcommon.shared.geoportal.project.LifecycleInformationDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.RelationshipDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.UseCaseDescriptorDV; import org.gcube.application.geoportalcommon.shared.products.ConcessioneDV; import org.gcube.application.geoportalcommon.shared.products.content.WorkspaceContentDV; @@ -83,10 +84,10 @@ public interface GeoportalDataEntryServiceAsync { void performActionSteps(String profileID, String projectID, ActionDefinitionDV action, AsyncCallback callback); - void getRelationshipNames(String profileID, AsyncCallback> callback); + void getRelationshipsDefinition(String profileID, AsyncCallback> callback); - void createRelationship(String fromProfileID, String fromProjectID, String relationshipName, String toProfileID, - String toProjectID, AsyncCallback callback); + void createRelationship(String fromProfileID, String fromProjectID, String relationshipID, String toProfileID, + String toProjectID, AsyncCallback callback); void getProjectByID(String profileID, String projectID, AsyncCallback callback); diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/events/CreateRelationHandlerEvent.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/events/CreateRelationHandlerEvent.java index 89f2fc9..9909833 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/events/CreateRelationHandlerEvent.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/events/CreateRelationHandlerEvent.java @@ -1,6 +1,7 @@ package org.gcube.portlets.user.geoportaldataentry.client.events; import org.gcube.application.geoportalcommon.shared.geoportal.ResultDocumentDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import com.google.gwt.event.shared.GwtEvent; @@ -9,13 +10,13 @@ public class CreateRelationHandlerEvent extends GwtEvent /** The type. */ public static Type TYPE = new Type(); private ResultDocumentDV fromProject; - private String relationshipName; + private RelationshipDefinitionDV relationSelected; private ResultDocumentDV toProject; - public CreateRelationHandlerEvent(ResultDocumentDV fromProject, String relationshipName, + public CreateRelationHandlerEvent(ResultDocumentDV fromProject, RelationshipDefinitionDV relationSelected, ResultDocumentDV toProject) { this.fromProject = fromProject; - this.relationshipName = relationshipName; + this.relationSelected = relationSelected; this.toProject = toProject; } @@ -55,8 +56,8 @@ public class CreateRelationHandlerEvent extends GwtEvent return fromProject; } - public String getRelationshipName() { - return relationshipName; + public RelationshipDefinitionDV getRelationSelected() { + return relationSelected; } public ResultDocumentDV getToProject() { diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/action/ActionListPanel.ui.xml b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/action/ActionListPanel.ui.xml index b230cc9..e2c1b51 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/action/ActionListPanel.ui.xml +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/action/ActionListPanel.ui.xml @@ -20,7 +20,7 @@ - MODERATION ACTIONS + WORKFLOW ACTIONS \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/projects/ListOfProjectTablePanel.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/projects/ListOfProjectTablePanel.java index f1f6071..21eef58 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/projects/ListOfProjectTablePanel.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/projects/ListOfProjectTablePanel.java @@ -25,6 +25,8 @@ import com.github.gwtbootstrap.client.ui.constants.AlertType; import com.github.gwtbootstrap.client.ui.constants.ButtonType; import com.github.gwtbootstrap.client.ui.constants.IconSize; import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyPressEvent; @@ -314,18 +316,27 @@ public class ListOfProjectTablePanel extends Composite { public void instanceAndShowListOfProjects(List ucdProjectTypesForListingDataView) { GWT.log("ListOfProjectTablePanel instanceAndShowListOfProjects called"); this.ucdProjectTypesForListingDataView = ucdProjectTypesForListingDataView; - // If the list of UCDProjectType for listing is not empty.. FIRE THE EVENT OF - // SELECTION on the first item - noProjectSelectionMessage.setVisible(true); - if (ucdProjectTypesForListingDataView.size() > 0) { - noProjectSelectionMessage.setVisible(false); - UseCaseDescriptorDV singleUCD = ucdProjectTypesForListingDataView.get(0); - alertProjectType.setText(singleUCD.getName()); - // setFilteringParameters(displayFields, sortByFields, searchForFields, - // currentSearchingFilter); - appManagerBus.fireEvent( - new GetListOfRecordsEvent(true, singleUCD.getProfileID(), getCurrentSearchingFilter(), true)); - } + + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + + @Override + public void execute() { + + noProjectSelectionMessage.setVisible(true); + // SELECTION on the first item + if (ucdProjectTypesForListingDataView.size() > 0) { + noProjectSelectionMessage.setVisible(false); + UseCaseDescriptorDV singleUCD = ucdProjectTypesForListingDataView.get(0); + alertProjectType.setText(singleUCD.getName()); + // setFilteringParameters(displayFields, sortByFields, searchForFields, + // currentSearchingFilter); + appManagerBus.fireEvent( + new GetListOfRecordsEvent(true, singleUCD.getProfileID(), getCurrentSearchingFilter(), true)); + } + + } + }); + } // /** diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/CreateRelationProjectsPanel.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/CreateRelationProjectsPanel.java index 2d9cef5..53588b4 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/CreateRelationProjectsPanel.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/CreateRelationProjectsPanel.java @@ -2,8 +2,10 @@ package org.gcube.portlets.user.geoportaldataentry.client.ui.relation; import java.util.HashMap; import java.util.List; +import java.util.Map; import org.gcube.application.geoportalcommon.shared.geoportal.ResultDocumentDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.portlets.user.geoportaldataentry.client.GeoPortalDataEntryApp; import org.gcube.portlets.user.geoportaldataentry.client.events.CloseCreateRelationGUIEvent; import org.gcube.portlets.user.geoportaldataentry.client.events.CreateRelationHandlerEvent; @@ -75,6 +77,8 @@ public class CreateRelationProjectsPanel extends Composite { @UiField Alert alertMessage; + + private Map mapRelationsDefiniton = new HashMap(); private HashMap selectedProjects = new HashMap(2); @@ -98,11 +102,11 @@ public class CreateRelationProjectsPanel extends Composite { listBoxRelationNames.setWidth("90%"); - GeoPortalDataEntryApp.geoportalDataEntryService.getRelationshipNames(project.getProfileID(), - new AsyncCallback>() { + GeoPortalDataEntryApp.geoportalDataEntryService.getRelationshipsDefinition(project.getProfileID(), + new AsyncCallback>() { @Override - public void onSuccess(List relationshipNames) { + public void onSuccess(List relationshipNames) { if (relationshipNames == null || relationshipNames.size() == 0) { buttCreateRelation.setEnabled(false); @@ -113,8 +117,9 @@ public class CreateRelationProjectsPanel extends Composite { return; } - for (String relName : relationshipNames) { - listBoxRelationNames.addItem(relName, relName); + for (RelationshipDefinitionDV relDef : relationshipNames) { + listBoxRelationNames.addItem(relDef.getLabel(), relDef.getId()); + mapRelationsDefiniton.put(relDef.getId(), relDef); } } @@ -166,8 +171,11 @@ public class CreateRelationProjectsPanel extends Composite { boolean isValidForm = checkFormPassed(); if (isValidForm) { buttCreateRelation.setEnabled(false); + + RelationshipDefinitionDV relationSelected = mapRelationsDefiniton.get(listBoxRelationNames.getSelectedValue()); + appManagerBus.fireEvent(new CreateRelationHandlerEvent(selectedProjects.get(0), - listBoxRelationNames.getSelectedItemText(), selectedProjects.get(1))); + relationSelected, selectedProjects.get(1))); } } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/ViewRelationshipPanel.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/ViewRelationshipPanel.java index 43653bd..d01502b 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/ViewRelationshipPanel.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/relation/ViewRelationshipPanel.java @@ -1,6 +1,7 @@ package org.gcube.portlets.user.geoportaldataentry.client.ui.relation; import java.util.HashMap; +import java.util.Map.Entry; import org.gcube.application.geoportalcommon.shared.geoportal.ResultDocumentDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.RelationshipDV; @@ -84,7 +85,8 @@ public class ViewRelationshipPanel extends Composite { firstProjectPanelContainer.clear(); secondProjectPanelContainer.clear(); - String htmlMsg = "" + project.getFirstEntryOfMap().getKey() + ": " + project.getFirstEntryOfMap().getValue() + Entry firstEntrySet = project.getFirstEntryOfMap(); + String htmlMsg = firstEntrySet.getKey() + ": " + firstEntrySet.getValue() + " (id: " + project.getId() + ")"; firstProjectPanelContainer.add(new HTML(htmlMsg)); @@ -107,8 +109,8 @@ public class ViewRelationshipPanel extends Composite { label.setText(relationDV.getRelationshipName()); flexTable.setWidget(0, 0, label); flexTable.setWidget(1, 0, new LoaderIcon("loading project..")); - GeoportalDataEntryServiceAsync.Util.getInstance().getResultDocumentFoProjectByID(project.getProfileID(), - project.getId(), new AsyncCallback() { + GeoportalDataEntryServiceAsync.Util.getInstance().getResultDocumentFoProjectByID(relationDV.getTargetUCD(), + relationDV.getTargetID(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { @@ -118,16 +120,17 @@ public class ViewRelationshipPanel extends Composite { @Override public void onSuccess(ResultDocumentDV result) { - String htmlMsg = "" + project.getFirstEntryOfMap().getValue() + " (id: " - + project.getId() + ")"; - + Entry firstEntrySet = result.getFirstEntryOfMap(); + String htmlMsg = firstEntrySet.getKey() + ": " + firstEntrySet.getValue() + + " (id: " + result.getId() + ")"; + flexTable.setWidget(1, 0, new HTML(htmlMsg)); } }); ReportTemplateToHTML rtth2 = new ReportTemplateToHTML("", project.getDocumentAsJSON(), false, false); - rtth.showAsJSON(false); + rtth2.showAsJSON(false); flexTable.setWidget(2, 0, rtth2); secondProjectPanelContainer.add(flexTable); diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java index 83ff2b7..c8f246b 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java @@ -13,6 +13,7 @@ import org.gcube.application.geoportal.client.utils.Serialization; import org.gcube.application.geoportal.common.model.document.Project; import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation; import org.gcube.application.geoportal.common.model.document.relationships.Relationship; +import org.gcube.application.geoportal.common.model.useCaseDescriptor.RelationshipDefinition; import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor; import org.gcube.application.geoportalcommon.ConvertToDataValueObjectModel; import org.gcube.application.geoportalcommon.ConvertToDataViewModel; @@ -40,6 +41,7 @@ import org.gcube.application.geoportalcommon.shared.geoportal.project.LifecycleI import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; import org.gcube.application.geoportalcommon.shared.geoportal.project.RelationshipDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.GEOPORTAL_DATA_HANDLER; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.application.geoportalcommon.shared.geoportal.ucd.UseCaseDescriptorDV; import org.gcube.application.geoportalcommon.shared.products.ConcessioneDV; import org.gcube.application.geoportalcommon.shared.products.content.WorkspaceContentDV; @@ -599,84 +601,71 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen throw new Exception("updateSectionForRecord not implemented!"); /* - if (itemId == null) - throw new Exception("Item id is null"); - - if (recordType.equalsIgnoreCase(RECORD_TYPE.CONCESSIONE.name())) { - SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); - MongoServiceUtil serviceUtil = new MongoServiceUtil(); - MongoConcessioni clientMongo = serviceUtil.getInstanceMongoConcessioni(); - - String toEditPath = null; - AddSectionToConcessioneRequest request = null; - List files = new ArrayList(); - - // Managing files already present as current content and kept by user - List keepFiles = serviceUtil.toTemFilesFromWSC(keepCurrentContent); - if (keepFiles != null) { - files.addAll(keepFiles); - LOG.debug(keepFiles.size() + " current corrent file/s has/have been added to list of files"); - } - - // Managing new files uploaded by user - List newFiles = serviceUtil.toTemFiles(gDBean.getFilesUploaded()); - if (newFiles != null) { - files.addAll(newFiles); - LOG.debug(newFiles.size() + " new file/s has/have been added to list of files"); - } - - // TODO MUST BE REVISITED - - - if (section.contains("abstract_relazione")) { - - toEditPath = Paths.ABSTRACT_RELAZIONE; request = new - AddSectionToConcessioneRequest(toEditPath, files); - - } else if (section.contains("immagini")) { toEditPath = - Paths.imgByIndex(pathIndex); request = new - AddSectionToConcessioneRequest(toEditPath, files); - - } else if (section.contains("relazione")) { toEditPath = Paths.RELAZIONE; - request = new AddSectionToConcessioneRequest(toEditPath, files); - - } else if (section.contains("posizionamentoScavo")) { toEditPath = - Paths.POSIZIONAMENTO; request = new - AddSectionToConcessioneRequest(toEditPath, files); - - } else if (section.contains("piante")) { toEditPath = - Paths.piantaByIndex(pathIndex); request = new - AddSectionToConcessioneRequest(toEditPath, files); } - - - // Unpublish - LOG.info("Unpublishing " + itemId); - clientMongo.unPublish(itemId); - - // update Fileset - LOG.info("Removing old fileset.. "); - Concessione concessione = clientMongo.cleanFileSet(itemId, toEditPath); - - LOG.debug("Sending new Fileset .."); - if (files.size() > 0) { - // StorageUtils storage=new StorageUtils(); - // Building TempFile - SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); - LOG.info("Registering FileSet into recordId " + itemId + " with request path: " + toEditPath - + " and: " + files.size() + " file/s"); - concessione = clientMongo.registerFileSet(itemId, request); - } else { - LOG.info("Fileset is empty, skipping registerFileSet"); - } - - LOG.info("Publishing itemId: " + itemId); - concessione = clientMongo.publish(itemId); - - LOG.debug("returning concessione: " + concessione); - return ConvertToDataViewModel.toConcessione(concessione); - } - - */ + * if (itemId == null) throw new Exception("Item id is null"); + * + * if (recordType.equalsIgnoreCase(RECORD_TYPE.CONCESSIONE.name())) { + * SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); + * MongoServiceUtil serviceUtil = new MongoServiceUtil(); MongoConcessioni + * clientMongo = serviceUtil.getInstanceMongoConcessioni(); + * + * String toEditPath = null; AddSectionToConcessioneRequest request = null; + * List files = new ArrayList(); + * + * // Managing files already present as current content and kept by user + * List keepFiles = serviceUtil.toTemFilesFromWSC(keepCurrentContent); + * if (keepFiles != null) { files.addAll(keepFiles); LOG.debug(keepFiles.size() + * + " current corrent file/s has/have been added to list of files"); } + * + * // Managing new files uploaded by user List newFiles = + * serviceUtil.toTemFiles(gDBean.getFilesUploaded()); if (newFiles != null) { + * files.addAll(newFiles); LOG.debug(newFiles.size() + + * " new file/s has/have been added to list of files"); } + * + * // TODO MUST BE REVISITED + * + * + * if (section.contains("abstract_relazione")) { + * + * toEditPath = Paths.ABSTRACT_RELAZIONE; request = new + * AddSectionToConcessioneRequest(toEditPath, files); + * + * } else if (section.contains("immagini")) { toEditPath = + * Paths.imgByIndex(pathIndex); request = new + * AddSectionToConcessioneRequest(toEditPath, files); + * + * } else if (section.contains("relazione")) { toEditPath = Paths.RELAZIONE; + * request = new AddSectionToConcessioneRequest(toEditPath, files); + * + * } else if (section.contains("posizionamentoScavo")) { toEditPath = + * Paths.POSIZIONAMENTO; request = new + * AddSectionToConcessioneRequest(toEditPath, files); + * + * } else if (section.contains("piante")) { toEditPath = + * Paths.piantaByIndex(pathIndex); request = new + * AddSectionToConcessioneRequest(toEditPath, files); } + * + * + * // Unpublish LOG.info("Unpublishing " + itemId); + * clientMongo.unPublish(itemId); + * + * // update Fileset LOG.info("Removing old fileset.. "); Concessione + * concessione = clientMongo.cleanFileSet(itemId, toEditPath); + * + * LOG.debug("Sending new Fileset .."); if (files.size() > 0) { // StorageUtils + * storage=new StorageUtils(); // Building TempFile + * SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); + * LOG.info("Registering FileSet into recordId " + itemId + + * " with request path: " + toEditPath + " and: " + files.size() + " file/s"); + * concessione = clientMongo.registerFileSet(itemId, request); } else { + * LOG.info("Fileset is empty, skipping registerFileSet"); } + * + * LOG.info("Publishing itemId: " + itemId); concessione = + * clientMongo.publish(itemId); + * + * LOG.debug("returning concessione: " + concessione); return + * ConvertToDataViewModel.toConcessione(concessione); } + * + */ } catch (Exception e) { LOG.error("Error on updating the project with item id: " + itemId, e); @@ -926,29 +915,39 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } /** - * Perform action steps. + * Gets the relationships definition. * * @param profileID the profile ID - * @param projectID the project ID - * @param action the action - * @return the project DV + * @return the relationships definition * @throws Exception the exception */ @Override - public List getRelationshipNames(String profileID) throws Exception { + public List getRelationshipsDefinition(String profileID) throws Exception { LOG.info("getRelationshipNames called for profileID {}", profileID); try { - List listRelationshipNames = SessionUtil.getRelationshipNames(getThreadLocalRequest(), profileID); - if (listRelationshipNames == null) { + List listRelDefinitionDV = SessionUtil + .getRelationshipsDefinition(getThreadLocalRequest(), profileID); + if (listRelDefinitionDV == null) { UseCaseDescriptorCaller client = GeoportalClientCaller.useCaseDescriptors(); SessionUtil.getCurrentContext(getThreadLocalRequest(), true); - listRelationshipNames = client.getRelationshipNames(profileID); - SessionUtil.setRelationshipNames(getThreadLocalRequest(), profileID, listRelationshipNames); + List listRelDefinition = client.getRelationshipDefinitions(profileID); + if (listRelDefinition == null || listRelDefinition.isEmpty()) { + listRelDefinitionDV = new ArrayList(1); + } else { + listRelDefinitionDV = new ArrayList(listRelDefinition.size()); + } + for (RelationshipDefinition relationshipDefinition : listRelDefinition) { + RelationshipDefinitionDV relDef = ConvertToDataValueObjectModel + .toRelationshipDefinition(relationshipDefinition); + listRelDefinitionDV.add(relDef); + } + + SessionUtil.setRelationshipDefinition(getThreadLocalRequest(), profileID, listRelDefinitionDV); } - return listRelationshipNames; + return listRelDefinitionDV; } catch (Exception e) { String error = "Error occurred on reading the relations config from UCD " + profileID; @@ -959,20 +958,26 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } + /** + * Creates the relationship. + * + * @param fromProfileID the from profile ID + * @param fromProjectID the from project ID + * @param relationshipId the relationship id + * @param toProfileID the to profile ID + * @param toProjectID the to project ID + * @return the relationship DV + * @throws Exception the exception + */ @Override - public RelationshipDV createRelationship(String fromProfileID, String fromProjectID, String relationshipName, + public void createRelationship(String fromProfileID, String fromProjectID, String relationshipId, String toProfileID, String toProjectID) throws Exception { LOG.info("createRelationship called"); try { ProjectsCaller projects = GeoportalClientCaller.projects(); - Relationship relationship = projects.createRelationship(fromProfileID, fromProjectID, relationshipName, - toProfileID, toProjectID); - - RelationshipDV relationshipDV = ConvertToDataValueObjectModel.toRelationshipDV(relationship); - LOG.info("returning: " + relationshipDV); - return relationshipDV; - + SessionUtil.getCurrentContext(getThreadLocalRequest(), true); + projects.createRelationship(fromProfileID, fromProjectID, relationshipId, toProfileID, toProjectID); } catch (Exception e) { String error = "Error occurred on creating the relationship"; LOG.error(error, e); @@ -982,12 +987,21 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } + /** + * Gets the project by ID. + * + * @param profileID the profile ID + * @param projectID the project ID + * @return the project by ID + * @throws Exception the exception + */ @Override public ProjectDV getProjectByID(String profileID, String projectID) throws Exception { LOG.info("getProjectByID called"); try { ProjectsCaller projects = GeoportalClientCaller.projects(); + SessionUtil.getCurrentContext(getThreadLocalRequest(), true); Project project = projects.getProjectByID(profileID, projectID); ProjectDVBuilder projectBuilder = ProjectDVBuilder.newBuilder().fullDocumentMap(true); ProjectDV projectDV = ConvertToDataValueObjectModel.toProjectDV(project, projectBuilder); @@ -1003,12 +1017,21 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen } + /** + * Gets the result document fo project by ID. + * + * @param profileID the profile ID + * @param projectID the project ID + * @return the result document fo project by ID + * @throws Exception the exception + */ @Override public ResultDocumentDV getResultDocumentFoProjectByID(String profileID, String projectID) throws Exception { LOG.info("getResultDocumentFoProjectByID called"); try { ProjectsCaller projects = GeoportalClientCaller.projects(); + SessionUtil.getCurrentContext(getThreadLocalRequest(), true); Project project = projects.getProjectByID(profileID, projectID); ResultDocumentDV documentDV = ConvertToDataValueObjectModel.toResultDocumentDV(project); LOG.info("returning: " + documentDV.getId()); diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/SessionUtil.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/SessionUtil.java index 501ce8f..6cd3bfd 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/SessionUtil.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/SessionUtil.java @@ -16,6 +16,7 @@ import org.gcube.application.geoportalcommon.GeoportalCommon; import org.gcube.application.geoportalcommon.shared.GNADataEntryConfigProfile; import org.gcube.application.geoportalcommon.shared.GNADataViewerConfigProfile; import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.RelationshipDefinitionDV; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.portal.PortalContext; import org.gcube.common.scope.api.ScopeProvider; @@ -45,7 +46,7 @@ public class SessionUtil { private static final String GEONA_DATAVIEWER_PROFILE = "GEONA_DATAVIEWER_PROFILE"; private static final String LIST_OF_CONCESSIONI = "LIST_OF_CONCESSIONI"; - private static final String LIST_OF_RELATIONS = "LIST_OF_RELATIONS"; + private static final String LIST_OF_RELATIONSHIP_DEFINITION = "LIST_OF_RELATIONSHIP_DEFINITION"; private static final String LIST_OF_PROJECTS = "LIST_OF_PROJECTS"; private static final String COUNT_DOCS_FOR_PROFILE_ID = "COUNT_DOCS_FOR_PROFILE_ID"; @@ -300,29 +301,30 @@ public class SessionUtil { } /** - * Gets the relationship names. + * Gets the relationships definition. * * @param httpServletRequest the http servlet request * @param profileID the profile ID - * @return the relationship names + * @return the relationships definition */ - public static List getRelationshipNames(HttpServletRequest httpServletRequest, String profileID) { + public static List getRelationshipsDefinition(HttpServletRequest httpServletRequest, + String profileID) { HttpSession session = httpServletRequest.getSession(); - return (List) session.getAttribute(LIST_OF_RELATIONS + profileID); + return (List) session.getAttribute(LIST_OF_RELATIONSHIP_DEFINITION + profileID); } /** - * Sets the relationship names. + * Sets the relationship definition. * * @param threadLocalRequest the thread local request * @param profileID the profile ID * @param listRelationshipNames the list relationship names */ - public static void setRelationshipNames(HttpServletRequest threadLocalRequest, String profileID, - List listRelationshipNames) { + public static void setRelationshipDefinition(HttpServletRequest threadLocalRequest, String profileID, + List listRelationshipNames) { HttpSession session = threadLocalRequest.getSession(); - session.setAttribute(LIST_OF_RELATIONS + profileID, listRelationshipNames); + session.setAttribute(LIST_OF_RELATIONSHIP_DEFINITION + profileID, listRelationshipNames); } } diff --git a/src/test/java/org/gcube/portlets/user/geoportaldataentry/Complex_Tests.java b/src/test/java/org/gcube/portlets/user/geoportaldataentry/Complex_Tests.java new file mode 100644 index 0000000..5ae32ca --- /dev/null +++ b/src/test/java/org/gcube/portlets/user/geoportaldataentry/Complex_Tests.java @@ -0,0 +1,161 @@ +package org.gcube.portlets.user.geoportaldataentry; + +import java.util.LinkedHashMap; +import java.util.List; + +import org.gcube.application.geoportal.common.model.document.Project; +import org.gcube.application.geoportal.common.model.useCaseDescriptor.HandlerDeclaration; +import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor; +import org.gcube.application.geoportalcommon.ConvertToDataValueObjectModel; +import org.gcube.application.geoportalcommon.ProjectDVBuilder; +import org.gcube.application.geoportalcommon.geoportal.GeoportalClientCaller; +import org.gcube.application.geoportalcommon.geoportal.ProjectsCaller; +import org.gcube.application.geoportalcommon.geoportal.UseCaseDescriptorCaller; +import org.gcube.application.geoportalcommon.shared.geoportal.ConfigurationDV; +import org.gcube.application.geoportalcommon.shared.geoportal.config.GcubeProfileDV; +import org.gcube.application.geoportalcommon.shared.geoportal.project.ProjectDV; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.GEOPORTAL_CONFIGURATION_TYPE; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.GEOPORTAL_DATA_HANDLER; +import org.gcube.application.geoportalcommon.shared.geoportal.ucd.HandlerDeclarationDV; +import org.gcube.common.authorization.library.provider.SecurityTokenProvider; +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.portlets.widgets.mpformbuilder.server.MetadataProfileFormBuilderServiceImpl; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetaDataProfileBean; +import org.gcube.portlets.widgets.mpformbuilder.shared.metadata.MetadataFieldWrapper; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jayway.jsonpath.JsonPath; + +public class Complex_Tests { + + private UseCaseDescriptorCaller clientUCD = null; + private ProjectsCaller clientPrj = null; + private static String CONTEXT = "/gcube/devsec/devVRE"; + private static String TOKEN = ""; // devVRE + private static String PROFILE_ID = "profiledConcessioni"; + + private static String PROJECT_ID = "630f905855e2947b0278c1a8"; + + public static final String JSON_$_POINTER = "$"; + private static final Logger LOG = LoggerFactory.getLogger(Complex_Tests.class); + + //@Before + public void init() { + ScopeProvider.instance.set(CONTEXT); + SecurityTokenProvider.instance.set(TOKEN); + clientPrj = GeoportalClientCaller.projects(); + clientUCD = GeoportalClientCaller.useCaseDescriptors(); + } + + //@Test + public void testReadProjectForUCDDataEntry() { + ScopeProvider.instance.set(CONTEXT); + SecurityTokenProvider.instance.set(TOKEN); + + try { + System.out.println("Loading UCD for PROFILE_ID: "+PROFILE_ID); + UseCaseDescriptor ucd = clientUCD.getUCDForId(PROFILE_ID); + GEOPORTAL_DATA_HANDLER theHandler = GEOPORTAL_DATA_HANDLER.geoportal_data_entry; + List handlers = ucd.getHandlersByType(theHandler.getType()); + + if (handlers.size() == 0) + throw new Exception("No handler " + theHandler + "found"); + + //Loading Handler gcube_profiles + HandlerDeclaration dataEntryHandler = handlers.get(0); + HandlerDeclarationDV handlerGcubeProfiles = ConvertToDataValueObjectModel + .toHandlerDeclarationDV(dataEntryHandler, ucd, GEOPORTAL_CONFIGURATION_TYPE.gcube_profiles); + + System.out.println("Handler "+GEOPORTAL_CONFIGURATION_TYPE.gcube_profiles+" for PROFILE_ID: "+PROFILE_ID); + System.out.println(handlerGcubeProfiles); + + ConfigurationDV config = handlerGcubeProfiles.getConfiguration(); + List listGcubeProfiles = toListGcubeProfiles(config); + System.out.println("List of GcubeProfileDV are: "+listGcubeProfiles); + + //Loading Metadata Profile from IS + MetadataProfileFormBuilderServiceImpl metaProfileBUilder = new MetadataProfileFormBuilderServiceImpl(); + LinkedHashMap> linkedHashProfiles = new LinkedHashMap>(); + for (GcubeProfileDV gcubeProfileDV : listGcubeProfiles) { + ScopeProvider.instance.set(CONTEXT); + SecurityTokenProvider.instance.set(TOKEN); + List listProfiles = metaProfileBUilder.getProfilesInTheScopeForName(CONTEXT, + gcubeProfileDV.getGcubeSecondaryType(), gcubeProfileDV.getGcubeName()); + String key = gcubeProfileDV.getGcubeSecondaryType()+gcubeProfileDV.getGcubeName(); + System.out.println("for key: "+key+ " readi profiles: "+listGcubeProfiles); + linkedHashProfiles.put(gcubeProfileDV.getGcubeSecondaryType()+gcubeProfileDV.getGcubeName(), listProfiles); + } + + Project theProject = clientPrj.getProjectByID(PROFILE_ID, PROJECT_ID); + ProjectDVBuilder projectBuilder = ProjectDVBuilder.newBuilder().fullDocumentMap(true); + ProjectDV theProjectDV = ConvertToDataValueObjectModel.toProjectDV(theProject, projectBuilder); + System.out.println("theProjectDV as JSON: "+theProject.getTheDocument().toJson()); + System.out.println("theProjectDV as MAP: "+theProjectDV.getTheDocument().getDocumentAsMap()); + + for (GcubeProfileDV gcubeProfileDV : listGcubeProfiles) { + + LOG.debug("The profile is: " + gcubeProfileDV); + + // Building JSON/section full PATH and section name + String sectionJSONPath = ""; + String parentPathFromProfile = gcubeProfileDV.getParentName() == null ? "" : gcubeProfileDV.getParentName(); + String theSectionName = gcubeProfileDV.getSectionName(); + + if (theSectionName.compareTo(JSON_$_POINTER) == 0 || theSectionName.compareTo(JSON_$_POINTER + ".") == 0) { + sectionJSONPath = JSON_$_POINTER; + theSectionName = ""; + } else { + sectionJSONPath = String.format("%s%s", + parentPathFromProfile.endsWith(".") ? parentPathFromProfile : parentPathFromProfile + ".", theSectionName); + } + LOG.debug("The sectionJSONPath is: " + sectionJSONPath); + + // Building Parent PATH + String parentPath = sectionJSONPath.compareTo(JSON_$_POINTER) == 0 ? JSON_$_POINTER + : sectionJSONPath.substring(0, sectionJSONPath.lastIndexOf(".")); + + JsonPath parentJSONPath = JsonPath.compile(parentPath); + + List theProfileBeans = linkedHashProfiles.get(gcubeProfileDV.getGcubeSecondaryType()+gcubeProfileDV.getGcubeName()); + MetaDataProfileBean theProfileBean = theProfileBeans.get(0); + for (MetadataFieldWrapper metadataField : theProfileBean.getMetadataFields()) { + String theFieldName = metadataField.getFieldId()!=null?metadataField.getFieldId():metadataField.getFieldName(); + theProjectDV.getTheDocument().getDocumentAsMap().get(linkedHashProfiles); + } + + } + + for (String key : linkedHashProfiles.keySet()) { + System.out.println("For key: "+key+" got profiles: "+linkedHashProfiles.get(key)); + + } + } catch (Exception e) { + System.out.println("error"); + e.printStackTrace(); + } + + System.out.println("termimated"); + } + + /** + * To list gcube profiles. + * + * @param config the config + * @return the list + */ + private List toListGcubeProfiles(ConfigurationDV config) { + + try { + return (List) config.getConfiguration(); + } catch (Exception e) { + System.err.println("Error on casting " + ConfigurationDV.class.getName() + " to List of " + + GcubeProfileDV.class.getName()); + } + + return null; + } + +}