From bcc5f729ae608df11865893742807b3f683e5add Mon Sep 17 00:00:00 2001 From: Massimiliano Assante Date: Fri, 8 Jun 2018 15:59:28 +0000 Subject: [PATCH] async version of getusers implementation almost finished git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/widgets/pickitem-widget@168992 82a268e6-3cf1-43bd-a215-b396298e98cf --- .classpath | 2 +- .settings/org.eclipse.jdt.core.prefs | 2 +- pom.xml | 72 ++++++++++---- .../client/dialog/PickItemsDialog.java | 81 ++++++++++----- .../pickitem/client/oracle/UserOracle.java | 60 ++++++++++++ .../client/oracle/UserSuggestion.java | 28 ++++++ .../pickitem/client/rpc/PickItemService.java | 12 +++ .../client/rpc/PickItemServiceAsync.java | 13 +++ .../pickitem/server/PickItemServiceImpl.java | 98 +++++++++++++++++++ 9 files changed, 322 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserOracle.java create mode 100644 src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserSuggestion.java create mode 100644 src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemService.java create mode 100644 src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemServiceAsync.java create mode 100644 src/main/java/org/gcube/portlets/widgets/pickitem/server/PickItemServiceImpl.java diff --git a/.classpath b/.classpath index f9194f1..f5d75fa 100644 --- a/.classpath +++ b/.classpath @@ -29,7 +29,7 @@ - + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 6249222..4d17cd3 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,6 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.7 org.eclipse.jdt.core.compiler.debug.lineNumber=generate diff --git a/pom.xml b/pom.xml index b006458..7c4ac3a 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.gcube.portlets.widgets pickitem-widget - 1.3.0-SNAPSHOT + 2.0.0-SNAPSHOT jar gCube Pick Item Widget @@ -27,7 +27,7 @@ 2.7.0 distro 1.7 - 1.7 + 1.8 ${project.build.directory}/${project.build.finalName} UTF-8 @@ -52,6 +52,36 @@ ${gwtVersion} provided + + javax.servlet + javax.servlet-api + provided + + + javax.portlet + portlet-api + provided + + + org.gcube.dvos + usermanagement-core + provided + + + com.liferay.portal + portal-service + provided + + + com.liferay.portal + util-java + provided + + + org.slf4j + slf4j-api + provided + @@ -66,8 +96,8 @@ maven-compiler-plugin - 1.7 - 1.7 + ${maven.compiler.source} + ${maven.compiler.target} @@ -144,23 +174,23 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java index ac7b725..468ef01 100644 --- a/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java +++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/dialog/PickItemsDialog.java @@ -1,10 +1,13 @@ package org.gcube.portlets.widgets.pickitem.client.dialog; import java.util.ArrayList; +import java.util.List; import org.gcube.portlets.widgets.pickitem.client.bundle.CssAndImages; import org.gcube.portlets.widgets.pickitem.client.events.PickedItemEvent; import org.gcube.portlets.widgets.pickitem.client.events.PickedItemEventHandler; +import org.gcube.portlets.widgets.pickitem.client.oracle.UserOracle; +import org.gcube.portlets.widgets.pickitem.client.oracle.UserSuggestion; import org.gcube.portlets.widgets.pickitem.client.uibinder.NoPhotoTemplate; import org.gcube.portlets.widgets.pickitem.client.uibinder.SelectableItem; import org.gcube.portlets.widgets.pickitem.client.uibinder.WithPhotoTemplate; @@ -55,7 +58,7 @@ public class PickItemsDialog extends PopupPanel { private int itemCursorIndexStart = -1; boolean handleNonCharKeys = false; - private final MultiWordSuggestOracle oracle = new MultiWordSuggestOracle(); + private MultiWordSuggestOracle oracle = new UserOracle(); //by default we use the async version; private int displayIndexSelected; @@ -70,7 +73,7 @@ public class PickItemsDialog extends PopupPanel { private boolean includeTriggerChar; //to explain private boolean stopListening = true; - + static { CssAndImages.INSTANCE.css().ensureInjected(); } @@ -84,6 +87,31 @@ public class PickItemsDialog extends PopupPanel { * @param includeTriggerChar true if your suggestions start with the trigger char (e.g. #anHashTag triggered by #) false otherwise */ public PickItemsDialog(char triggerChar, ArrayList beans, final HandlerManager eventBus, int widthInPixel) { + this(triggerChar, eventBus, widthInPixel); + this.beans = beans; + oracle = new MultiWordSuggestOracle(); //not async version + GWT.log("new constructor"); + //add the user fill names to the oracle + for (ItemBean bean : beans) { + oracle.add(bean.getAlternativeName()); + + // if it is a team, set the avatar + if(bean.isItemGroup()) + bean.setThumbnailURL(CssAndImages.INSTANCE.iconTeam().getSafeUri().toString()); + + } + } + + /** + * Use this constructor for users, the list of the users is automatically loaded form the VRE members if in a VRE or from the union of the current's user VRE members if at root level + * Note that you must declare the pick item widget servlet in this case + * @param triggerChar the 'single char' used to trigger the items list show, e.g. '@', '#' .... + * @param eventBus the event bus on where the widget will fire the selected user event + * @param widthInPixel the desired width (grater than 199 pixel) + * @param hasPhoto tell of you have want to show photo for the item or not + * @param includeTriggerChar true if your suggestions start with the trigger char (e.g. #anHashTag triggered by #) false otherwise + */ + public PickItemsDialog(char triggerChar, final HandlerManager eventBus, int widthInPixel) { super(true, false); if (widthInPixel < 200) { throw new IllegalArgumentException("width must be greater than 199"); @@ -92,23 +120,17 @@ public class PickItemsDialog extends PopupPanel { this.triggerChar = triggerChar; this.includeTriggerChar = false; this.hasPhoto = false; - this.beans = beans; + this.beans = new ArrayList<>(); focusPanel.setWidth(widthInPixel+"px"); mainPanel.setWidth(widthInPixel+"px"); setWidth(widthInPixel+"px"); focusPanel.add(mainPanel); setWidget(focusPanel); - setStyleName("pickDialog"); - - //add the user fill names to the oracle - for (ItemBean bean : beans) { - oracle.add(bean.getAlternativeName()); - - // if it is a team, set the avatar - if(bean.isItemGroup()) - bean.setThumbnailURL(CssAndImages.INSTANCE.iconTeam().getURL()); - - } + setStyleName("pickDialog"); + if (oracle instanceof UserOracle) { + UserOracle asyncOracle = (UserOracle) oracle; + asyncOracle.addContacts(getAllUsers()); + } //remove the first selected when hovering focusPanel.addMouseOverHandler(new MouseOverHandler() { @@ -133,15 +155,21 @@ public class PickItemsDialog extends PopupPanel { handleMouseDown(); } }); - + eventBus.addHandler(PickedItemEvent.TYPE, new PickedItemEventHandler() { @Override public void onSelectedItem(PickedItemEvent event) { - GWT.log("GOT @ CAZZEVENT! "+ event.getSelectedItem().getAlternativeName()); + GWT.log("GOT EVENT "+ event.getSelectedItem().getAlternativeName()); stopListening = true; } }); } + //just used in devlopment + private List getAllUsers() { + List toReturn = new ArrayList<>(); + toReturn.add(new ItemBean("andrea.rossi", "andrea.rossi", "Andrea Rossi", "m.assante@gmail.com")); + return toReturn; + } /** * use if you have want to show a photo for the item or not, remember to provide it in {@link ItemBean} instances */ @@ -181,10 +209,10 @@ public class PickItemsDialog extends PopupPanel { this.itemCursorIndexStart = cursorPos; } else { - + itemCursorIndexEnd = cursorPos; currText = currText.substring(itemCursorIndexStart, cursorPos)+ch; - + if (currText.contains(""+triggerChar) && currText.length() > 1 && !stopListening) { if (pickingUser(currText.substring(1))) { handleNonCharKeys = true; @@ -216,6 +244,7 @@ public class PickItemsDialog extends PopupPanel { * @param currText the text being typed */ private boolean pickingUser(String currText) { + GWT.log("ci arriva"); if (currText.trim().length() > 0) { if (includeTriggerChar) showSuggestions(triggerChar+currText); @@ -293,14 +322,20 @@ public class PickItemsDialog extends PopupPanel { } }); } + } - + private ItemBean getUserModelBySuggestion(Suggestion suggestion) { - for (ItemBean bean : beans) { - if (suggestion.getReplacementString().compareTo(bean.getAlternativeName()) ==0) - return bean; + if (suggestion instanceof UserSuggestion) { + UserSuggestion us = (UserSuggestion) suggestion; + return us.getUser(); + } else { //the user were preloaded client side + for (ItemBean bean : beans) { + if (suggestion.getReplacementString().compareTo(bean.getAlternativeName()) ==0) + return bean; + } + return new ItemBean("no-match","no-match","no-match","no-match"); } - return new ItemBean("no-match","no-match","no-match","no-match"); } private Widget getUserTemplate(ItemBean user, int displayIndex, boolean hasPhoto) { diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserOracle.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserOracle.java new file mode 100644 index 0000000..fe511de --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserOracle.java @@ -0,0 +1,60 @@ +package org.gcube.portlets.widgets.pickitem.client.oracle; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.gcube.portlets.widgets.pickitem.client.rpc.PickItemService; +import org.gcube.portlets.widgets.pickitem.client.rpc.PickItemServiceAsync; +import org.gcube.portlets.widgets.pickitem.shared.ItemBean; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.MultiWordSuggestOracle; + +public class UserOracle extends MultiWordSuggestOracle{ + private final PickItemServiceAsync pickuserService = GWT.create(PickItemService.class); + + private List contacts = new LinkedList<>(); + + public void addContacts(List users) { + contacts.addAll(users); + } + + public UserOracle() { + //((ServiceDefTarget) pickuserService).setServiceEntryPoint(Utils.getServiceEntryPoint()); + } + + @Override + public void requestSuggestions(final Request request, final Callback callback) { + GWT.log("UserOracl requestSuggestions"); + final Response resp = new Response(); + if(contacts.isEmpty()){ + GWT.log("callback.onSuggestionsReady"); + callback.onSuggestionsReady(request, resp); + return; + } + String text = request.getQuery(); + text = text.toLowerCase(); + + final List list = new ArrayList<>(); + GWT.log("calling searchEntities ..." + text); + pickuserService.searchEntities(text, new AsyncCallback>() { + + @Override + public void onFailure(Throwable arg0) { + GWT.log("error"); + callback.onSuggestionsReady(request, resp); + return; + } + + @Override + public void onSuccess(ArrayList results) { + for (ItemBean contact : results){ + list.add(new UserSuggestion(contact)); + } + resp.setSuggestions(list); + callback.onSuggestionsReady(request, resp); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserSuggestion.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserSuggestion.java new file mode 100644 index 0000000..119f119 --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/oracle/UserSuggestion.java @@ -0,0 +1,28 @@ +package org.gcube.portlets.widgets.pickitem.client.oracle; + +import org.gcube.portlets.widgets.pickitem.shared.ItemBean; + +import com.google.gwt.user.client.ui.SuggestOracle; + +public class UserSuggestion implements SuggestOracle.Suggestion { + + private ItemBean user; + + public UserSuggestion(ItemBean user) { + this.user = user; + } + + @Override + public String getDisplayString() { + return user.getAlternativeName(); + } + + @Override + public String getReplacementString() { + return user.getAlternativeName(); + } + + public ItemBean getUser() { + return user; + } +} diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemService.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemService.java new file mode 100644 index 0000000..94ba678 --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemService.java @@ -0,0 +1,12 @@ +package org.gcube.portlets.widgets.pickitem.client.rpc; + +import java.util.ArrayList; + +import org.gcube.portlets.widgets.pickitem.shared.ItemBean; + +import com.google.gwt.user.client.rpc.RemoteService; +import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; +@RemoteServiceRelativePath("pickItemServlet") +public interface PickItemService extends RemoteService { + ArrayList searchEntities(String keyword); +} diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemServiceAsync.java b/src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemServiceAsync.java new file mode 100644 index 0000000..ac7888a --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/pickitem/client/rpc/PickItemServiceAsync.java @@ -0,0 +1,13 @@ +package org.gcube.portlets.widgets.pickitem.client.rpc; + +import java.util.ArrayList; + +import org.gcube.portlets.widgets.pickitem.shared.ItemBean; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +public interface PickItemServiceAsync { + + void searchEntities(String keyword, AsyncCallback> callback); + +} diff --git a/src/main/java/org/gcube/portlets/widgets/pickitem/server/PickItemServiceImpl.java b/src/main/java/org/gcube/portlets/widgets/pickitem/server/PickItemServiceImpl.java new file mode 100644 index 0000000..f2b52c7 --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/pickitem/server/PickItemServiceImpl.java @@ -0,0 +1,98 @@ +package org.gcube.portlets.widgets.pickitem.server; + + +import java.util.ArrayList; +import java.util.List; + +import org.gcube.portlets.widgets.pickitem.client.rpc.PickItemService; +import org.gcube.portlets.widgets.pickitem.shared.ItemBean; +import org.gcube.vomanagement.usermanagement.exception.UserManagementSystemException; +import org.gcube.vomanagement.usermanagement.exception.UserRetrievalFault; +import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; +import org.gcube.vomanagement.usermanagement.util.ManagementUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gwt.user.server.rpc.RemoteServiceServlet; +import com.liferay.portal.kernel.dao.orm.QueryUtil; +import com.liferay.portal.kernel.exception.PortalException; +import com.liferay.portal.kernel.exception.SystemException; +import com.liferay.portal.kernel.util.OrderByComparator; +import com.liferay.portal.kernel.util.OrderByComparatorFactoryUtil; +import com.liferay.portal.model.User; +import com.liferay.portal.service.UserLocalServiceUtil; + +@SuppressWarnings("serial") +public class PickItemServiceImpl extends RemoteServiceServlet implements PickItemService { + private static final Logger _log = LoggerFactory.getLogger(PickItemServiceImpl.class); + /** + * + * @return true if you're running into the portal, false if in development + */ + private boolean isWithinPortal() { + try { + UserLocalServiceUtil.getService(); + return true; + } + catch (com.liferay.portal.kernel.bean.BeanLocatorException ex) { + _log.trace("Development Mode ON"); + return false; + } + } +//TODO: Questo metodo lunedì va modificato per fargli cercare non tutti gli utenti ma dipdende dallo scope i VRE Members oppure l'unione se è root, e poi vanno gestiti i gruppi stessa cosa. +//anzi dovresti farti passare come parametro la VRE dove è stato postato il post allora sarebbe semplicissimo, niente union non serve + @Override + public ArrayList searchEntities(String keyword) { + ArrayList toReturn = new ArrayList<>(); + if (isWithinPortal()) { + OrderByComparator comparator = OrderByComparatorFactoryUtil.create("User_", "screenname", true); + try { + _log.debug("Searching " + keyword); + List lrUsers = UserLocalServiceUtil.search(ManagementUtils.getCompany().getCompanyId(), keyword, 0, null, QueryUtil.ALL_POS, QueryUtil.ALL_POS, comparator); + for (User user : lrUsers) { + toReturn.add(new ItemBean(""+user.getUserId(), user.getScreenName(), user.getFullName(), getUserImagePortraitUrlLocal(user.getScreenName()))); + } + } catch (SystemException | PortalException e) { + e.printStackTrace(); + } + } else { //development + for (int i = 0; i < 10; i++) { + toReturn.add(new ItemBean("andrea.rossi", "andrea.rossi", "Andrea Rossi", "m.assante@gmail.com")); + if (i % 2 == 0) + toReturn.add(new ItemBean(""+i, "username"+i, "userGetFullname()"+i, "user.getEmail()"+i)); + else + toReturn.add(new ItemBean(""+i, "ciccio"+i, "ciccioNome"+i, "ciccioEMail"+i)); + } + } + return toReturn; + } + /** + * this method is needed because user images portrait change id depending on the portal instance + * e.g. a post made from iMarine portal would not show the avatarIMage in D4Science.org + * @param screenname + * @return the url of the image portrait for this portal instance + */ + private String getUserImagePortraitUrlLocal(String screenName) { + if (! isWithinPortal()) { + return ""; + } + String thumbnailURL = ""; + try { + thumbnailURL = new LiferayUserManager().getUserByUsername(screenName).getUserAvatarURL(); + } catch (UserManagementSystemException | UserRetrievalFault e) { + e.printStackTrace(); + } + return thumbnailURL; + } + /** + * utility method extract the @domain.com from an email address + * return @unknown-domain in case of no emails + */ + private String extractDomainFromEmail(String email) { + int index = email.indexOf('@'); + if (index > 0) + return email.substring(index); + else + return "@unknown-domain"; + } +}