package org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server; import static org.gcube.common.authorization.client.Constants.authorizationService; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpSession; import org.apache.commons.codec.binary.Base64; import org.gcube.common.authorization.client.exceptions.ObjectNotFound; import org.gcube.common.authorization.library.provider.UserInfo; import org.gcube.common.portal.PortalContext; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory; import org.gcube.datacatalogue.ckanutillibrary.server.utils.CatalogueUtilMethods; import org.gcube.datacatalogue.ckanutillibrary.server.utils.SessionCatalogueAttributes; import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg; import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService; import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.server.thread.UpdateItemCatalogueResource; import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.BeanUserInOrgGroupRole; import org.gcube.portlets.gcubeckan.gcubeckandatacatalog.shared.CkanConnectorAccessPoint; import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.OrganizationBean; import org.gcube.vomanagement.usermanagement.GroupManager; import org.gcube.vomanagement.usermanagement.impl.LiferayGroupManager; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import eu.trentorise.opendata.jackan.model.CkanGroup; import eu.trentorise.opendata.jackan.model.CkanOrganization; /** * The server side implementation of the RPC service. * * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it * @author Costantino Perciante costantino.perciante@isti.cnr.it * Jun 10, 2016 */ @SuppressWarnings("serial") public class GcubeCkanDataCatalogServiceImpl extends RemoteServiceServlet implements GcubeCkanDataCatalogService { public static final String UTF_8 = "UTF-8"; private static final String PORT_HTTP = ":80"; private static final String PORT_HTTPS = ":443"; private static final String HTTPS = "https"; private static final String HTTP = "http"; public static String CKANCONNECTORCONTEXT = "CkanConnectorContext"; public static String CKANCONNECTORLOGOUT = "CkanConnectorLogout"; private static final Log logger = LogFactoryUtil.getLog(GcubeCkanDataCatalogServiceImpl.class); private static final String VIEW_PER_ORGANIZATION_LIFERAY_CUSTOM_FIELD = "ViewPerVRECatalogue"; private static final Map checksItemCatalogueResourceUpdated = new ConcurrentHashMap(); /** * Instanciate the ckan util library. * Since it needs the scope, we need to check if it is null or not * * @param discoverScope if you want to the discover the utils library in this specified scope * @return the catalogue */ public DataCatalogue getCatalogue(String discoverScope){ String currentScope = SessionUtil.getCurrentContext(getThreadLocalRequest(), false); DataCatalogue instance = null; try{ String scopeInWhichDiscover = discoverScope != null && !discoverScope.isEmpty() ? discoverScope : currentScope; logger.debug("Discovering ckan utils library into scope " + scopeInWhichDiscover); instance = DataCatalogueFactory.getFactory().getUtilsPerScope(scopeInWhichDiscover); }catch(Exception e){ logger.error("Unable to retrieve ckan utils. Error was: ",e); } return instance; } /* (non-Javadoc) * @see org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService#getCKanConnector(java.lang.String, java.lang.String) */ @Override public CkanConnectorAccessPoint getCKanConnector(String browserLocationURL, String pathInfoParameter, String queryStringParameters) throws Exception { logger.info("getCKanConnector [browserLocationURL: "+browserLocationURL+ " ]"); logger.info("getCKanConnector [pathInfo: "+pathInfoParameter + ", query: "+queryStringParameters+"]"); try{ // just get the current scope and set it into ScopeProvider... SessionUtil.getCurrentContext(getThreadLocalRequest(), true); // retrieve scope per current portlet url String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); if(queryStringParameters!=null && Base64.isBase64(queryStringParameters.getBytes())){ byte[] valueDecoded=Base64.decodeBase64(queryStringParameters.getBytes()); queryStringParameters = new String(valueDecoded); logger.info("queryStringParameters detected like Base64 and decoded like: "+queryStringParameters); } if(SessionUtil.isIntoPortal()){ ScopeBean scopeBean = new ScopeBean(scopePerCurrentUrl); if(scopeBean.is(Type.VRE) && !checksItemCatalogueResourceUpdated.containsKey(scopePerCurrentUrl)){ new UpdateItemCatalogueResource(scopePerCurrentUrl, SessionUtil.getCurrentClientUrl(getThreadLocalRequest()).split("\\?")[0]).start(); checksItemCatalogueResourceUpdated.put(scopePerCurrentUrl, true); } } if(pathInfoParameter == null || pathInfoParameter.isEmpty()){ //pathInfoParameter is null or empty, in this case we are pointing to the Catalogue Home pathInfoParameter = isViewPerVREEnabled(browserLocationURL); } CkanConnectorAccessPoint ckAP = getCkanConnectorAccessPoint(browserLocationURL, pathInfoParameter, queryStringParameters, scopePerCurrentUrl); SessionUtil.saveCkanAccessPoint(this.getThreadLocalRequest().getSession(), scopePerCurrentUrl, ckAP); logger.info("Built the URI to CKAN (connector in case of user logged): "+ckAP.buildURI()); logger.debug("returning ckanConnectorUri: "+ckAP); return ckAP; }catch(Exception e ){ String message = "Sorry an error occurred while contacting gCube Ckan Data Catalogue"; logger.error(message, e); throw new Exception(message); } } /** * Gets the ckan connector access point. * * @param browserLocationURL the browser location URL * @param pathInfoParameter the path info parameter * @param queryStringParameters the query string parameters * @param scopePerCurrentUrl the scope per current url * @return the ckan connector access point * @throws Exception the exception */ private CkanConnectorAccessPoint getCkanConnectorAccessPoint(String browserLocationURL, String pathInfoParameter, String queryStringParameters, String scopePerCurrentUrl) throws Exception { if(outsideLoginPortal()){ CkanConnectorAccessPoint ckan = new CkanConnectorAccessPoint(getCatalogue(scopePerCurrentUrl).getCatalogueUrl(),""); ckan.setOutsideLoginOnPortal(true); ckan.addPathInfo(pathInfoParameter); ckan.addQueryString(queryStringParameters); return ckan; } //CKAN BASE URL GcoreEndpointReader ckanEndPoint = null; try{ ckanEndPoint = SessionUtil.getCkanEndPoint(this.getThreadLocalRequest().getSession(), scopePerCurrentUrl); }catch(Exception e){ logger.error("CkanConnectorAccessPoint error: "+e.getMessage()); throw new Exception("Sorry, an error occurred during contacting d4Science Data Catalogue, try again later"); } String ckanConnectorBaseUrl = ckanEndPoint.getCkanResourceEntyName(); ckanConnectorBaseUrl = ckanConnectorBaseUrl.startsWith(HTTP) && !ckanConnectorBaseUrl.startsWith(HTTPS)?ckanConnectorBaseUrl.replaceFirst(HTTP, HTTPS):ckanConnectorBaseUrl; ckanConnectorBaseUrl = ckanConnectorBaseUrl.contains(PORT_HTTP)?ckanConnectorBaseUrl.replace(PORT_HTTP, PORT_HTTPS):ckanConnectorBaseUrl; logger.debug("Base URL is: "+ckanConnectorBaseUrl); //GET CONTEXT String ckanContext = getServletContext().getInitParameter(CKANCONNECTORCONTEXT); logger.debug(CKANCONNECTORCONTEXT + " is: "+ckanContext); ckanContext= ckanContext!=null?ckanContext:""; CkanConnectorAccessPoint ckan = new CkanConnectorAccessPoint(ckanConnectorBaseUrl, ckanContext); pathInfoParameter = CkanConnectorAccessPoint.checkURLPathSeparator(pathInfoParameter, true, false); logger.debug("External Path Info parameter: "+pathInfoParameter); //ADD PATH INFO ckan.addPathInfo(pathInfoParameter); logger.debug("CKanConnector pathInfo: "+ckan.getPathInfoParameter()); ckan.addQueryString(queryStringParameters); //GET TOKEN String gcubeTokenValue = null; gcubeTokenValue = getGcubeSecurityToken(scopePerCurrentUrl); // set the token into the CkanConnectorAccessPoint ckan.addGubeToken(gcubeTokenValue); //ADDING LIST OF VRE TO WHICH USER BELONGS if(!SessionUtil.isIntoPortal()){ return ckan; } // retrieve the list of VREs to whom the user belongs (actually one vre at most is sent) Map roleForVre = UserUtil.getVreRoleForUser( SessionUtil.getCurrentUser( getThreadLocalRequest()).getEmail(), scopePerCurrentUrl, getCatalogue(scopePerCurrentUrl), isViewPerVREEnabled(browserLocationURL) != null, getThreadLocalRequest().getSession()); ckan.addListOfVREs(roleForVre); return ckan; } /** * Gets the gcube security token for the user in current session and for a given scope. * * @param context the context * @return the gcube security token * @throws Exception the exception */ protected String getGcubeSecurityToken(String context) throws Exception { // ask it directly to the auth service String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); String token = null; try{ logger.debug("Checking if token for user " + username + " in context " + context + " already exists..."); //ADDED by Francesco Mangiacrapa if(SessionUtil.isIntoPortal()) { token = authorizationService().resolveTokenByUserAndContext(username, context); logger.debug("It exists!"); }else { logger.debug("Out of portal, I'm reading the user token from PortalContext"); token = PortalContext.getConfiguration().getCurrentUserToken(username,context); } }catch(ObjectNotFound e){ logger.info("Creating token for user " + username + " and context " + context); token = authorizationService().generateUserToken(new UserInfo(username, new ArrayList()), context); logger.debug("received token: "+ token.substring(0, 5) + "***********************"); } return token; } /* (non-Javadoc) * @see org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService#getMyRole() */ @Override public RolesCkanGroupOrOrg getMyRole(){ // base role as default value RolesCkanGroupOrOrg toReturn = RolesCkanGroupOrOrg.MEMBER; if(!SessionUtil.isIntoPortal()){ logger.warn("OUT FROM PORTAL DETECTED RETURNING ROLE: "+RolesCkanGroupOrOrg.ADMIN); toReturn = RolesCkanGroupOrOrg.ADMIN; }else{ HttpSession httpSession = this.getThreadLocalRequest().getSession(); String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); // get the scope String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); // get key per scope String keyPerScopeRole = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_HIGHEST_ROLE, scopePerCurrentUrl); String keyPerScopeOrganizations = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_ORGANIZATIONS_PUBLISH_KEY, scopePerCurrentUrl); String keyPerScopeGroups = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_GROUPS_MEMBER, scopePerCurrentUrl); // check into session if(httpSession.getAttribute(keyPerScopeRole) != null){ toReturn = (RolesCkanGroupOrOrg)httpSession.getAttribute(keyPerScopeRole); logger.info("Found user role into session " + toReturn + " and it is going to be returned for user " + username); }else{ try{ GroupManager gm = new LiferayGroupManager(); String groupName = gm.getGroup(gm.getGroupIdFromInfrastructureScope(scopePerCurrentUrl)).getGroupName(); // we build up also a list that keeps track of the scopes (orgs) in which the user has at least role EDITOR List orgsInWhichAtLeastEditorRole = new ArrayList(); toReturn = UserUtil.getHighestRole(scopePerCurrentUrl, username, groupName, this, orgsInWhichAtLeastEditorRole); // put role in session httpSession.setAttribute(keyPerScopeRole, toReturn); logger.info("Set role " + toReturn + " into session for user " + username); // if he is an admin/editor preload: // 1) organizations in which he can publish (the widget will find these info in session) // 2) the list of groups if(!toReturn.equals(RolesCkanGroupOrOrg.MEMBER)){ httpSession.setAttribute(keyPerScopeOrganizations, orgsInWhichAtLeastEditorRole); httpSession.setAttribute(keyPerScopeGroups, fetchUserGroups(scopePerCurrentUrl, username)); } }catch(Exception e){ logger.error("Error while retreving roles... returning " + toReturn, e); } } } logger.debug("Returning highest role " + toReturn); // return the role return toReturn; } /** * Fetch the list of ckan groups for which the user is member. * * @param context the context * @param username the username * @return the list */ private List fetchUserGroups(String context, String username) { List toReturn = null; logger.info("Preloading user's groups"); try{ DataCatalogue catalogue = getCatalogue(context); String apiKey = catalogue.getApiKeyFromUsername(username); toReturn = new ArrayList(); Map> mapRoleGroup = catalogue.getUserRoleByGroup(username, apiKey); Set>> set = mapRoleGroup.entrySet(); for (Entry> entry : set) { Set> subSet = entry.getValue().entrySet(); for (Entry subEntry : subSet) { toReturn.add(new OrganizationBean(subEntry.getKey().getTitle(), subEntry.getKey().getName(), false)); } } logger.debug("List of groups to return is " + toReturn); }catch(Exception e){ logger.error("Failed to preload user's groups"); } return toReturn; } // @Override // public String logoutURIFromCkan() { // String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); // // // get the scope from session // String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); // // CkanConnectorAccessPoint ckanAP = SessionUtil.getCkanAccessPoint(this.getThreadLocalRequest().getSession(), scopePerCurrentUrl); // logger.info("Logout from CKAN for: "+username +" by token: "+ckanAP.getGcubeTokenValue()); // // String ckanConnectorLogut = getServletContext().getInitParameter(CKANCONNECTORLOGOUT); // logger.debug(CKANCONNECTORLOGOUT + " is: "+ckanConnectorLogut); // // CkanConnectorAccessPoint ckan = new CkanConnectorAccessPoint(ckanAP.getBaseUrl(), ckanConnectorLogut); // ckan.addGubeToken(ckanAP.getGcubeTokenValue()); // return ckan.buildURI(); // } /* (non-Javadoc) * @see org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService#logoutFromCkan() */ @Override public String logoutFromCkanURL() { // check if the portlet is accessed from outside the portal if(outsideLoginPortal()) return null; HttpSession httpSession = this.getThreadLocalRequest().getSession(); String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); if(username == null){ logger.warn("User is null"); return null; } logger.info("Getting CKAN Logout URL..."); String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); CkanConnectorAccessPoint ckanAP = SessionUtil.getCkanAccessPoint(httpSession, scopePerCurrentUrl); // String token = getGcubeSecurityToken(); logger.info("Logout from CKAN for: "+username ); logger.info(" by token: "+ckanAP.getGcubeTokenValue() +", the scope is: "+scopePerCurrentUrl); String ckanConnectorLogout = getServletContext().getInitParameter(CKANCONNECTORLOGOUT); logger.debug(GcubeCkanDataCatalogServiceImpl.CKANCONNECTORLOGOUT + " is: "+ckanConnectorLogout); CkanConnectorAccessPoint ckan = new CkanConnectorAccessPoint(ckanAP.getBaseUrl(), ckanConnectorLogout); ckan.addGubeToken(ckanAP.getGcubeTokenValue()); String deleteURI = ckan.buildURI(); logger.debug(GcubeCkanDataCatalogServiceImpl.CKANCONNECTORLOGOUT + " returning: "+deleteURI); return deleteURI; } /* (non-Javadoc) * @see org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService#getCkanOrganizationsNamesAndUrlsForUser() */ @Override public List getCkanOrganizationsNamesAndUrlsForUser() { List toReturn = new ArrayList(); if(!SessionUtil.isIntoPortal()){ logger.warn("You are not into the portal"); BeanUserInOrgGroupRole org = new BeanUserInOrgGroupRole("testVRE", "/organization/devvre", RolesCkanGroupOrOrg.ADMIN); toReturn.add(org); }else{ HttpSession httpSession = this.getThreadLocalRequest().getSession(); String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); // retrieve scope per current portlet url String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); String keyPerScope = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_ORGS_USER_KEY, scopePerCurrentUrl); // check if the aslsession already has such information if(httpSession.getAttribute(keyPerScope) != null){ toReturn = (List) httpSession.getAttribute(keyPerScope); logger.debug("List of organizations was into the session " + toReturn); }else{ logger.debug("Organizations list wasn't into session, retrieving them"); DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl); String apiKey = catalogue.getApiKeyFromUsername(username); Map> mapRoleGroup = catalogue.getUserRoleByOrganization(username, apiKey); Set>> set = mapRoleGroup.entrySet(); for (Entry> entry : set) { Set> subSet = entry.getValue().entrySet(); for (Entry subEntry : subSet) { BeanUserInOrgGroupRole org = new BeanUserInOrgGroupRole(subEntry.getKey().getTitle(), "/organization/" + subEntry.getKey().getName(), subEntry.getValue()); toReturn.add(org); } } logger.debug("List of organizations to return for user " + username + " is " + toReturn); httpSession.setAttribute(keyPerScope, toReturn); } } return toReturn; } /* (non-Javadoc) * @see org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService#getCkanGroupsNamesAndUrlsForUser() */ @Override public List getCkanGroupsNamesAndUrlsForUser() { List toReturn = new ArrayList(); if(!SessionUtil.isIntoPortal()){ logger.warn("You are not into the portal"); BeanUserInOrgGroupRole org = new BeanUserInOrgGroupRole("testGroup", "/group/testgroup", RolesCkanGroupOrOrg.MEMBER); toReturn.add(org); }else{ HttpSession httpSession = getThreadLocalRequest().getSession(); String username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); // retrieve scope per current portlet url String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); String keyPerScope = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_GROUPS_USER_KEY, scopePerCurrentUrl); // check if the aslsession already has such information if(httpSession.getAttribute(keyPerScope) != null){ toReturn = (List) httpSession.getAttribute(keyPerScope); logger.debug("List of groups was into the session " + toReturn); }else{ logger.debug("Groups list wasn't into session, retrieving them"); DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl); String apiKey = catalogue.getApiKeyFromUsername(username); Map> mapRoleGroup = catalogue.getUserRoleByGroup(username, apiKey); Set>> set = mapRoleGroup.entrySet(); for (Entry> entry : set) { Set> subSet = entry.getValue().entrySet(); for (Entry subEntry : subSet) { BeanUserInOrgGroupRole org = new BeanUserInOrgGroupRole(subEntry.getKey().getTitle(), "/group/" + subEntry.getKey().getName(), subEntry.getValue()); toReturn.add(org); } } logger.debug("List of groups to return for user " + username + " is " + toReturn); httpSession.setAttribute(keyPerScope, toReturn); } } return toReturn; } /* * Returns true either you are outside gateway (in eclipse mode) * or you are on the gateway and the user is not logged (i.e. public VRE catalogue) * */ @Override public boolean outsideLoginPortal() { if(!SessionUtil.isIntoPortal()){ logger.warn("You are in DEV mode"); return false; }else{ String username = null; try{ username = SessionUtil.getCurrentUser(getThreadLocalRequest()).getUsername(); }catch(Exception e){ logger.warn("Maybe there is no user "); } return username == null || username.isEmpty(); } } /* (non-Javadoc) * @see org.gcube.portlets.gcubeckan.gcubeckandatacatalog.client.GcubeCkanDataCatalogService#isManageProductEnabled() */ @Override public boolean isManageProductEnabled() { logger.info("Checking if the manage product button needs to be shown or not for the current context"); String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl); if(catalogue == null){ logger.warn("There is no catalogue instance here..., returning false"); return false; } else{ try{ boolean toReturn = catalogue.isManageProductEnabled(); logger.info("Will manage product be enabled for this user? " + Boolean.toString(toReturn)); return toReturn; }catch(Exception e){ logger.error("Unable to determine if the manage product needs to be shown or not", e); return false; } } } /** * Ask to liferay. * * @param browserLocationURL the browser location URL * @return the string */ @Override public String isViewPerVREEnabled(String browserLocationURL){ String toReturn = null; String scopePerCurrentUrl = SessionUtil.getScopeFromClientUrl(getThreadLocalRequest());// the view per vre can be managed independently for each context SessionUtil.getScopeFromClientUrl(getThreadLocalRequest()); //String scopePerCurrentUrl = PortalContext.getConfiguration().getCurrentScope(getThreadLocalRequest()); logger.debug("isViewPerVREEnabled called, read context: " + scopePerCurrentUrl); boolean enabled = false; try{ if(!SessionUtil.isIntoPortal()){ enabled = false; logger.warn("Enabling View per VRE in DEV mode? "+enabled); if(enabled) return "/organization_vre/" + scopePerCurrentUrl.substring(scopePerCurrentUrl.lastIndexOf("/")+1,scopePerCurrentUrl.length()).toLowerCase(); //is the VRE name return null; } GroupManager gm = new LiferayGroupManager(); enabled = (boolean) gm.readCustomAttr(gm.getGroupIdFromInfrastructureScope(scopePerCurrentUrl), VIEW_PER_ORGANIZATION_LIFERAY_CUSTOM_FIELD); if(enabled){ String groupName = gm.getGroup(gm.getGroupIdFromInfrastructureScope(scopePerCurrentUrl)).getGroupName().toLowerCase(); logger.info("VRE name (toLowerCase) read by LF GroupManager is: "+groupName); String secureVREName = "/"+groupName+"/"; if(browserLocationURL.toLowerCase().contains(secureVREName)){ //this should mean the caller (the location URL) is from VRE environment logger.info("The browserLocationURL: "+browserLocationURL+ " contains the string /VRE name/ '"+secureVREName+"'. The Catalogue Portlet should be at VRE level, reading configuration isViewPerVREEnabled"); toReturn = "/organization_vre/" + groupName; }else { //this should mean the caller is out from VRE environment,so should be a public or gateway catalogue logger.info("The browserLocationURL: "+browserLocationURL+ " DOES NOT contain the string /VRE name/ '"+secureVREName+"'. The Catalogue Portlet should NOT be at VRE level. Ignoring configuration isViewPerVREEnabled"); } } logger.debug("Read value for " + VIEW_PER_ORGANIZATION_LIFERAY_CUSTOM_FIELD + " is " + enabled + " and path is " + toReturn); }catch(Exception e){ logger.error("Failed to parse custom field value", e); } return toReturn; } }