/*
* JBoss, a division of Red Hat
* Copyright 2011, Red Hat Middleware, LLC, and individual
* contributors as indicated by the @authors tag. See the
* copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.gatein.wsrp.producer.handlers;
import com.google.common.base.Function;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.gatein.common.i18n.LocalizedString;
import org.gatein.common.logging.Logger;
import org.gatein.common.logging.LoggerFactory;
import org.gatein.common.util.ParameterValidation;
import org.gatein.exports.ExportManager;
import org.gatein.exports.data.ExportContext;
import org.gatein.exports.data.ExportPortletData;
import org.gatein.pc.api.InvalidPortletIdException;
import org.gatein.pc.api.NoSuchPortletException;
import org.gatein.pc.api.Portlet;
import org.gatein.pc.api.PortletInvokerException;
import org.gatein.pc.api.PortletStateType;
import org.gatein.pc.api.info.PortletInfo;
import org.gatein.pc.api.info.PreferenceInfo;
import org.gatein.pc.api.info.PreferencesInfo;
import org.gatein.pc.api.state.DestroyCloneFailure;
import org.gatein.pc.api.state.PropertyChange;
import org.gatein.pc.api.state.PropertyMap;
import org.gatein.registration.Registration;
import org.gatein.registration.RegistrationLocal;
import org.gatein.wsrp.WSRPConstants;
import org.gatein.wsrp.WSRPExceptionFactory;
import org.gatein.wsrp.WSRPTypeFactory;
import org.gatein.wsrp.WSRPUtils;
import org.gatein.wsrp.producer.PortletManagementInterface;
import org.gatein.wsrp.producer.Utils;
import org.gatein.wsrp.producer.WSRPProducerImpl;
import org.gatein.wsrp.spec.v2.ErrorCodes;
import org.gatein.wsrp.spec.v2.WSRP2ExceptionFactory;
import org.oasis.wsrp.v2.AccessDenied;
import org.oasis.wsrp.v2.ClonePortlet;
import org.oasis.wsrp.v2.CopiedPortlet;
import org.oasis.wsrp.v2.CopyPortlets;
import org.oasis.wsrp.v2.CopyPortletsResponse;
import org.oasis.wsrp.v2.DestroyPortlets;
import org.oasis.wsrp.v2.DestroyPortletsResponse;
import org.oasis.wsrp.v2.ExportByValueNotSupported;
import org.oasis.wsrp.v2.ExportPortlets;
import org.oasis.wsrp.v2.ExportPortletsResponse;
import org.oasis.wsrp.v2.ExportedPortlet;
import org.oasis.wsrp.v2.Extension;
import org.oasis.wsrp.v2.FailedPortlets;
import org.oasis.wsrp.v2.GetPortletDescription;
import org.oasis.wsrp.v2.GetPortletProperties;
import org.oasis.wsrp.v2.GetPortletPropertyDescription;
import org.oasis.wsrp.v2.GetPortletsLifetime;
import org.oasis.wsrp.v2.GetPortletsLifetimeResponse;
import org.oasis.wsrp.v2.ImportPortlet;
import org.oasis.wsrp.v2.ImportPortlets;
import org.oasis.wsrp.v2.ImportPortletsFailed;
import org.oasis.wsrp.v2.ImportPortletsResponse;
import org.oasis.wsrp.v2.ImportedPortlet;
import org.oasis.wsrp.v2.InconsistentParameters;
import org.oasis.wsrp.v2.InvalidHandle;
import org.oasis.wsrp.v2.InvalidRegistration;
import org.oasis.wsrp.v2.InvalidUserCategory;
import org.oasis.wsrp.v2.Lifetime;
import org.oasis.wsrp.v2.MissingParameters;
import org.oasis.wsrp.v2.ModifyRegistrationRequired;
import org.oasis.wsrp.v2.OperationFailed;
import org.oasis.wsrp.v2.OperationNotSupported;
import org.oasis.wsrp.v2.PortletContext;
import org.oasis.wsrp.v2.PortletDescription;
import org.oasis.wsrp.v2.PortletDescriptionResponse;
import org.oasis.wsrp.v2.PortletPropertyDescriptionResponse;
import org.oasis.wsrp.v2.Property;
import org.oasis.wsrp.v2.PropertyDescription;
import org.oasis.wsrp.v2.PropertyList;
import org.oasis.wsrp.v2.RegistrationContext;
import org.oasis.wsrp.v2.ReleaseExport;
import org.oasis.wsrp.v2.ResetProperty;
import org.oasis.wsrp.v2.ResourceList;
import org.oasis.wsrp.v2.ResourceSuspended;
import org.oasis.wsrp.v2.SetExportLifetime;
import org.oasis.wsrp.v2.SetPortletProperties;
import org.oasis.wsrp.v2.SetPortletsLifetime;
import org.oasis.wsrp.v2.SetPortletsLifetimeResponse;
import org.oasis.wsrp.v2.UserContext;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Handles PortletManagement calls on behalf of the producer.
*
* @author <a href="mailto:chris.laprun@jboss.com">Chris Laprun</a>
* @version $Revision: 11147 $
* @since 2.4
*/
public class PortletManagementHandler extends ServiceHandler implements PortletManagementInterface
{
private static final String GET_PORTLET_PROPERTY_DESCRIPTION = "GetPortletPropertyDescription";
private static final String GET_PORTLET_PROPERTIES = "GetPortletProperties";
private static final String PORTLET_CONTEXT = "PortletContext";
private static final String GET_PORTLET_DESCRIPTION = "GetPortletDescription";
private static final Logger log = LoggerFactory.getLogger(PortletManagementHandler.class);
public PortletManagementHandler(WSRPProducerImpl producer)
{
super(producer);
}
public PortletDescriptionResponse getPortletDescription(GetPortletDescription getPortletDescription)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(getPortletDescription, GET_PORTLET_DESCRIPTION);
Registration registration = producer.getRegistrationOrFailIfInvalid(getPortletDescription.getRegistrationContext());
PortletContext portletContext = getPortletDescription.getPortletContext();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(portletContext, PORTLET_CONTEXT, GET_PORTLET_DESCRIPTION);
UserContext userContext = getPortletDescription.getUserContext();
checkUserAuthorization(userContext);
// RegistrationLocal.setRegistration is called further down the invocation in ServiceDescriptionHandler.getPortletDescription
final List<String> desiredLocales = WSRPUtils.replaceByEmptyListIfNeeded(getPortletDescription.getDesiredLocales());
PortletDescription description = producer.getPortletDescription(portletContext, desiredLocales, registration);
return WSRPTypeFactory.createPortletDescriptionResponse(description);
}
public PortletPropertyDescriptionResponse getPortletPropertyDescription(GetPortletPropertyDescription getPortletPropertyDescription)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(getPortletPropertyDescription, GET_PORTLET_PROPERTY_DESCRIPTION);
PortletContext portletContext = getPortletPropertyDescription.getPortletContext();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(portletContext, PORTLET_CONTEXT, GET_PORTLET_PROPERTY_DESCRIPTION);
try
{
Registration registration = producer.getRegistrationOrFailIfInvalid(getPortletPropertyDescription.getRegistrationContext());
RegistrationLocal.setRegistration(registration);
UserContext userContext = getPortletPropertyDescription.getUserContext();
checkUserAuthorization(userContext);
Portlet portlet = getPortletFrom(portletContext, registration);
PortletInfo info = portlet.getInfo();
PreferencesInfo prefsInfo = info.getPreferences();
List<PropertyDescription> descs = Collections.emptyList();
if (prefsInfo != null)
{
Set keySet = prefsInfo.getKeys();
descs = new ArrayList<PropertyDescription>(keySet.size());
for (Object key : keySet)
{
PreferenceInfo prefInfo = prefsInfo.getPreference((String)key);
// WSRP Spec 8.7: return only the portion of the Portlet's persistent state the user is allowed to modify
// if read only status is not determined, we consider it as being read-only to be safe
Boolean readOnly = prefInfo.isReadOnly();
if (readOnly != null && !readOnly)
{
//todo: check what we should use key
//todo: right now we only support String properties
List<String> desiredLocales = getPortletPropertyDescription.getDesiredLocales();
desiredLocales = WSRPUtils.replaceByEmptyListIfNeeded(desiredLocales);
PropertyDescription desc = WSRPTypeFactory.createPropertyDescription(prefInfo.getKey(), WSRPConstants.XSD_STRING);
desc.setLabel(Utils.convertToWSRPLocalizedString(prefInfo.getDisplayName(), desiredLocales));
desc.setHint(Utils.convertToWSRPLocalizedString(prefInfo.getDescription(), desiredLocales));
descs.add(desc);
}
}
}
return WSRPTypeFactory.createPortletPropertyDescriptionResponse(descs);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public PortletContext clonePortlet(ClonePortlet clonePortlet)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(clonePortlet, "ClonePortlet");
PortletContext portletContext = clonePortlet.getPortletContext();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(portletContext, "PortletContext", "ClonePortlet");
Registration registration = producer.getRegistrationOrFailIfInvalid(clonePortlet.getRegistrationContext());
UserContext userContext = clonePortlet.getUserContext();
checkUserAuthorization(userContext);
org.gatein.pc.api.PortletContext portalPC = WSRPUtils.convertToPortalPortletContext(portletContext);
try
{
RegistrationLocal.setRegistration(registration);
org.gatein.pc.api.PortletContext response = producer.getPortletInvoker().createClone(PortletStateType.OPAQUE, portalPC);
return WSRPUtils.convertToWSRPPortletContext(response);
}
catch (NoSuchPortletException e)
{
throw WSRP2ExceptionFactory.throwWSException(InvalidHandle.class, "Failed to create clone for portlet '" + portletContext.getPortletHandle(), e);
}
catch (InvalidPortletIdException e)
{
throw WSRP2ExceptionFactory.throwWSException(InconsistentParameters.class, "Failed to create clone for portlet '" + portletContext.getPortletHandle(), e);
}
catch (PortletInvokerException e)
{
throw WSRP2ExceptionFactory.throwWSException(OperationFailed.class, "Failed to create clone for portlet '" + portletContext.getPortletHandle(), e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public DestroyPortletsResponse destroyPortlets(DestroyPortlets destroyPortlets)
throws InconsistentParameters, InvalidRegistration, MissingParameters, ModifyRegistrationRequired,
OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(destroyPortlets, "DestroyPortlets");
List<String> handles = destroyPortlets.getPortletHandles();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(handles, "portlet handles to be destroyed", "DestroyPortlets");
handles = WSRPUtils.replaceByEmptyListIfNeeded(handles);
Registration registration = producer.getRegistrationOrFailIfInvalid(destroyPortlets.getRegistrationContext());
List<org.gatein.pc.api.PortletContext> portletContexts = new ArrayList<org.gatein.pc.api.PortletContext>(handles.size());
for (String handle : handles)
{
portletContexts.add(org.gatein.pc.api.PortletContext.createPortletContext(handle));
}
try
{
RegistrationLocal.setRegistration(registration);
List<DestroyCloneFailure> failuresList = producer.getPortletInvoker().destroyClones(portletContexts);
int failuresNumber = failuresList.size();
List<FailedPortlets> failedPortlets;
if (failuresNumber > 0)
{
// for each reason of failure, record the associated portlet handles, expecting one portlet handle per message
Multimap<String, String> reasonToHandles = HashMultimap.create(failuresNumber, 1);
for (DestroyCloneFailure failure : failuresList)
{
reasonToHandles.put(failure.getMessage(), failure.getPortletId());
}
// create a FailedPortlets object for each reason
failedPortlets = new ArrayList<FailedPortlets>(reasonToHandles.size());
for (String reason : reasonToHandles.keys())
{
failedPortlets.add(WSRPTypeFactory.createFailedPortlets(reasonToHandles.get(reason), ErrorCodes.Codes.OPERATIONFAILED, reason));
}
}
else
{
failedPortlets = null;
}
return WSRPTypeFactory.createDestroyPortletsResponse(failedPortlets);
}
catch (PortletInvokerException e)
{
throw WSRP2ExceptionFactory.throwWSException(OperationFailed.class, "Failed to destroy clones", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public GetPortletsLifetimeResponse getPortletsLifetime(GetPortletsLifetime getPortletsLifetime)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, ModifyRegistrationRequired,
OperationFailed, OperationNotSupported, ResourceSuspended
{
throw WSRP2ExceptionFactory.throwWSException(OperationNotSupported.class, "Lifetime operations are not currently supported.", null);
}
public SetPortletsLifetimeResponse setPortletsLifetime(SetPortletsLifetime setPortletsLifetime)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, ModifyRegistrationRequired,
OperationFailed, OperationNotSupported, ResourceSuspended
{
throw WSRP2ExceptionFactory.throwWSException(OperationNotSupported.class, "Lifetime operations are not currently supported.", null);
}
public CopyPortletsResponse copyPortlets(CopyPortlets copyPortlets)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(copyPortlets, "copyPortlets");
List<PortletContext> portletContexts = copyPortlets.getFromPortletContexts();
if (!ParameterValidation.existsAndIsNotEmpty(portletContexts) || WSRPUtils.isSingletonListWithNullOrEmptyElement(portletContexts))
{
throw WSRP2ExceptionFactory.createWSException(MissingParameters.class, "Missing required portletContext in CopyPortlets.", null);
}
Registration fromRegistration = producer.getRegistrationOrFailIfInvalid(copyPortlets.getFromRegistrationContext());
RegistrationContext toRegistationContext = copyPortlets.getToRegistrationContext();
//if toRegistrationContext is null, then we use the fromRegistrationContext (from spec).
//NOTE: this means we can't move between a PortletContext on a registered consumer to a non-registered consumer
// between two non-registered consumers will still be ok.
if (toRegistationContext == null)
{
toRegistationContext = copyPortlets.getFromRegistrationContext();
}
Registration toRegistration = producer.getRegistrationOrFailIfInvalid(toRegistationContext);
UserContext fromUserContext = copyPortlets.getFromUserContext();
checkUserAuthorization(fromUserContext);
UserContext toUserContext = copyPortlets.getToUserContext();
checkUserAuthorization(toUserContext);
try
{
RegistrationLocal.setRegistration(fromRegistration);
Map<String, FailedPortlets> failedPortletsMap = new HashMap<String, FailedPortlets>(portletContexts.size());
List<CopiedPortlet> copiedPortlets = new ArrayList<CopiedPortlet>(portletContexts.size());
for (PortletContext portletContext : portletContexts)
{
try
{
org.gatein.pc.api.PortletContext portalPC = WSRPUtils.convertToPortalPortletContext(portletContext);
//NOTE: There are two ways we can do a copy. We can export using one registration and import using another. This seems the most straightforward way to do this, just seems a little overkill.
// OR we can copy the portlet, then use the RegistrationManager and RegistrationPolicy to delete the PC from one registration and add it to another. But we don't actually
// create the copy under the toRegistration and we would need to add extra checks here to make sure the toRegistration has the proper permissions.
// Not sure why there is even a copy portlet operation since it can be replicated by an export and then an import operation.
org.gatein.pc.api.PortletContext exportedPortletContext = producer.getPortletInvoker().exportPortlet(PortletStateType.OPAQUE, portalPC);
//Change the registration to the new registration and try and do an import. This should force the new import to be under the new registration context
RegistrationLocal.setRegistration(toRegistration);
org.gatein.pc.api.PortletContext copiedPortletContext = producer.getPortletInvoker().importPortlet(PortletStateType.OPAQUE, exportedPortletContext);
PortletContext wsrpClonedPC = WSRPUtils.convertToWSRPPortletContext(copiedPortletContext);
CopiedPortlet copiedPortlet = WSRPTypeFactory.createCopiedPortlet(wsrpClonedPC, portletContext.getPortletHandle());
copiedPortlets.add(copiedPortlet);
}
catch (Exception e)
{
if (log.isWarnEnabled())
{
log.warn("Error occured while trying to export a portlet.", e);
}
ErrorCodes.Codes errorCode;
String reason;
final String message = e.getLocalizedMessage();
if (e instanceof NoSuchPortletException || e instanceof InvalidHandle
|| (e instanceof IllegalArgumentException && message != null && message.contains(org.gatein.pc.api.PortletContext.INVALID_PORTLET_CONTEXT)))
{
errorCode = ErrorCodes.Codes.INVALIDHANDLE;
reason = "The specified portlet handle is invalid";
}
else // default error message.
{
errorCode = ErrorCodes.Codes.OPERATIONFAILED;
reason = "Error preparing portlet for export";
}
if (!failedPortletsMap.containsKey(errorCode.name()))
{
List<String> portletHandles = new ArrayList<String>();
portletHandles.add(portletContext.getPortletHandle());
FailedPortlets failedPortlets = WSRPTypeFactory.createFailedPortlets(portletHandles, errorCode, reason);
failedPortletsMap.put(errorCode.name(), failedPortlets);
}
else
{
FailedPortlets failedPortlets = failedPortletsMap.get(errorCode.name());
failedPortlets.getPortletHandles().add(portletContext.getPortletHandle());
}
}
}
List<FailedPortlets> failedPortlets = new ArrayList<FailedPortlets>(failedPortletsMap.values());
//TODO: handle resources properly
ResourceList resourceList = null;
return WSRPTypeFactory.createCopyPortletsResponse(copiedPortlets, failedPortlets, resourceList);
}
catch (Exception e)
{
throw WSRP2ExceptionFactory.throwWSException(OperationFailed.class, "Operation Failed while trying to CopyPortlets.", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public PortletContext setPortletProperties(SetPortletProperties setPortletProperties)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(setPortletProperties, "SetPortletProperties");
PortletContext portletContext = setPortletProperties.getPortletContext();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(portletContext, "PortletContext", "SetPortletProperties");
PropertyList propertyList = setPortletProperties.getPropertyList();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(propertyList, "PropertyList", "SetPortletProperties");
Registration registration = producer.getRegistrationOrFailIfInvalid(setPortletProperties.getRegistrationContext());
checkUserAuthorization(setPortletProperties.getUserContext());
List<Property> properties = propertyList.getProperties();
properties = WSRPUtils.replaceByEmptyListIfNeeded(properties);
List<ResetProperty> resetProperties = propertyList.getResetProperties();
resetProperties = WSRPUtils.replaceByEmptyListIfNeeded(resetProperties);
int changesCount = 0;
if (ParameterValidation.existsAndIsNotEmpty(properties))
{
changesCount += properties.size();
// check that we don't set and reset the same property
if (ParameterValidation.existsAndIsNotEmpty(resetProperties))
{
List<QName> names = new ArrayList<QName>(WSRPUtils.transform(properties, new Function<Property, QName>()
{
public QName apply(Property from)
{
return from.getName();
}
}));
names.retainAll(WSRPUtils.transform(resetProperties, new Function<ResetProperty, QName>()
{
public QName apply(ResetProperty from)
{
return from.getName();
}
}));
if (!names.isEmpty())
{
WSRP2ExceptionFactory.throwWSException(InconsistentParameters.class,
"Attempted to set and reset at the same time the following properties: " + names, null);
}
}
}
if (ParameterValidation.existsAndIsNotEmpty(resetProperties))
{
changesCount += resetProperties.size();
}
if (changesCount > 0)
{
List<PropertyChange> changes = new ArrayList<PropertyChange>(changesCount);
if (properties != null)
{
for (Property property : properties)
{
String value = property.getStringValue();
// todo: deal with XML values...
// List<Object> values = property.getAny();
// todo: deal with language?
// String lang = property.getLang();
changes.add(PropertyChange.newUpdate(property.getName().toString(), value));
}
}
if (resetProperties != null)
{
for (ResetProperty resetProperty : resetProperties)
{
changes.add(PropertyChange.newReset(resetProperty.getName().toString()));
}
}
try
{
RegistrationLocal.setRegistration(registration);
org.gatein.pc.api.PortletContext resultContext =
producer.getPortletInvoker().setProperties(WSRPUtils.convertToPortalPortletContext(portletContext),
changes.toArray(new PropertyChange[changes.size()]));
return WSRPUtils.convertToWSRPPortletContext(resultContext);
}
catch (NoSuchPortletException e)
{
throw WSRP2ExceptionFactory.throwWSException(InvalidHandle.class, "Failed to set properties for portlet '" + portletContext.getPortletHandle() + "'", e);
}
catch (InvalidPortletIdException e)
{
throw WSRP2ExceptionFactory.throwWSException(InconsistentParameters.class, "Failed to set properties for portlet '" + portletContext.getPortletHandle() + "'", e);
}
catch (PortletInvokerException e)
{
throw WSRP2ExceptionFactory.throwWSException(OperationFailed.class, "Failed to set properties for portlet '" + portletContext.getPortletHandle() + "'", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
return portletContext;
}
public PropertyList getPortletProperties(GetPortletProperties getPortletProperties)
throws AccessDenied, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(getPortletProperties, GET_PORTLET_PROPERTIES);
PortletContext portletContext = getPortletProperties.getPortletContext();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(portletContext, PORTLET_CONTEXT, GET_PORTLET_PROPERTIES);
Registration registration = producer.getRegistrationOrFailIfInvalid(getPortletProperties.getRegistrationContext());
UserContext userContext = getPortletProperties.getUserContext();
checkUserAuthorization(userContext);
List<String> names = getPortletProperties.getNames();
names = WSRPUtils.replaceByEmptyListIfNeeded(names);
Set<String> keys = new HashSet<String>(names);
try
{
PropertyMap properties;
org.gatein.pc.api.PortletContext jbpContext = WSRPUtils.convertToPortalPortletContext(portletContext);
RegistrationLocal.setRegistration(registration);
if (!keys.isEmpty())
{
properties = producer.getPortletInvoker().getProperties(jbpContext, keys);
}
else
{
properties = producer.getPortletInvoker().getProperties(jbpContext);
}
//todo: we need to check that the user can actually modify the properties
Portlet portlet = getPortletFrom(portletContext, registration);
PortletInfo info = portlet.getInfo();
PropertyList result = WSRPTypeFactory.createPropertyList();
int propertyNb = properties.size();
if (propertyNb > 0)
{
PreferenceInfo prefInfo;
String key;
List<String> values;
LocalizedString displayName;
for (Map.Entry<String, List<String>> entry : properties.entrySet())
{
key = entry.getKey();
values = entry.getValue();
prefInfo = info.getPreferences().getPreference(key);
String lang = WSRPConstants.DEFAULT_LOCALE;
if (prefInfo != null)
{
displayName = prefInfo.getDisplayName();
if (displayName != null)
{
lang = WSRPUtils.toString(displayName.getDefaultLocale());
}
}
// todo: support multi-valued properties
if (values.size() != 1)
{
throw new UnsupportedOperationException("Currently doesn't support multi-valued properties!");
}
result.getProperties().add(WSRPTypeFactory.createProperty(key, lang, values.get(0))); //todo: check what we should use key
}
}
return result;
}
catch (PortletInvokerException e)
{
throw WSRP2ExceptionFactory.throwWSException(InvalidHandle.class, "Could not retrieve properties for portlet '" + portletContext + "'", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public ExportPortletsResponse exportPortlets(ExportPortlets exportPortlets) throws AccessDenied,
ExportByValueNotSupported, InconsistentParameters, InvalidHandle, InvalidRegistration, InvalidUserCategory,
MissingParameters, ModifyRegistrationRequired, OperationFailed, OperationNotSupported, ResourceSuspended
{
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(exportPortlets, "ExportPortlets", "ExportPortlets");
List<PortletContext> portletContexts = exportPortlets.getPortletContext();
if (!ParameterValidation.existsAndIsNotEmpty(portletContexts) || WSRPUtils.isSingletonListWithNullOrEmptyElement(portletContexts))
{
throw WSRP2ExceptionFactory.createWSException(MissingParameters.class, "Missing required list of portlets to export in ExportPortlets.", null);
}
Registration registration = producer.getRegistrationOrFailIfInvalid(exportPortlets.getRegistrationContext());
UserContext userContext = exportPortlets.getUserContext();
checkUserAuthorization(userContext);
boolean exportByValueRequired;
if (exportPortlets.isExportByValueRequired() != null)
{
exportByValueRequired = exportPortlets.isExportByValueRequired();
}
else
{
exportByValueRequired = false;
}
//check that the export manager can handle export by value
final ExportManager exportManager = producer.getExportManager();
if (exportByValueRequired && !exportManager.supportsExportByValue())
{
//TODO: instead of passing a string here, we should pass a resource so that its localized
WSRP2ExceptionFactory.throwWSException(ExportByValueNotSupported.class, "The consumer is requesting portlets to be exported by value, but this consumer only supports export by reference.", null);
}
List<ExportedPortlet> exportedPortlets = new ArrayList<ExportedPortlet>(portletContexts.size());
Map<String, FailedPortlets> failedPortletsMap = new HashMap<String, FailedPortlets>(portletContexts.size());
try
{
RegistrationLocal.setRegistration(registration);
ExportContext exportContext;
final Lifetime askedLifetime = exportPortlets.getLifetime();
if (askedLifetime != null)
{
final XMLGregorianCalendar askedLifetimeCurrentTime = askedLifetime.getCurrentTime();
long currentTime = toLongDate(askedLifetimeCurrentTime);
long terminationTime = toLongDate(askedLifetime.getTerminationTime());
long refreshDuration = askedLifetime.getRefreshDuration().getTimeInMillis(askedLifetimeCurrentTime.toGregorianCalendar());
exportContext = exportManager.createExportContext(exportByValueRequired, currentTime, terminationTime, refreshDuration);
}
else
{
exportContext = exportManager.createExportContext(exportByValueRequired, -1, -1, -1);
}
for (PortletContext portletContext : portletContexts)
{
try
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(portletContext, "Portlet context");
String portletHandle = portletContext.getPortletHandle();
WSRP2ExceptionFactory.throwMissingParametersIfValueIsMissing(portletHandle, "Portlet handle", "PortletContext");
org.gatein.pc.api.PortletContext portalPC = WSRPUtils.convertToPortalPortletContext(portletContext);
org.gatein.pc.api.PortletContext exportedPortalPC = producer.getPortletInvoker().exportPortlet(PortletStateType.OPAQUE, portalPC);
if (exportedPortalPC == null)
{
WSRP2ExceptionFactory.throwWSException(InvalidHandle.class, "Could not find a portlet with handle " + portletHandle + " in the producer", null);
}
byte[] portletState = WSRPUtils.getStateOrNullFor(exportedPortalPC);
//get the exportPortletData
ExportPortletData exportPortletData = exportManager.createExportPortletData(exportContext, portletHandle, portletState);
//Create the exportedPortlet
byte[] exportPortletBytes = exportManager.encodeExportPortletData(exportContext, exportPortletData);
ExportedPortlet exportedPortlet = WSRPTypeFactory.createExportedPortlet(portletHandle, exportPortletBytes);
exportedPortlets.add(exportedPortlet);
}
catch (Exception e)
{
if (log.isWarnEnabled())
{
log.warn("Error occured while trying to export a portlet.", e);
}
ErrorCodes.Codes errorCode;
String reason;
if (e instanceof NoSuchPortletException || e instanceof InvalidHandle)
{
errorCode = ErrorCodes.Codes.INVALIDHANDLE;
reason = "The specified portlet handle is invalid";
}
else // default error message.
{
errorCode = ErrorCodes.Codes.OPERATIONFAILED;
reason = "Error preparing portlet for export";
}
final String errorCodeName = errorCode.name();
if (!failedPortletsMap.containsKey(errorCodeName))
{
List<String> portletHandles = new ArrayList<String>();
portletHandles.add(portletContext.getPortletHandle());
FailedPortlets failedPortlets = WSRPTypeFactory.createFailedPortlets(portletHandles, errorCode, reason);
failedPortletsMap.put(errorCodeName, failedPortlets);
}
else
{
FailedPortlets failedPortlets = failedPortletsMap.get(errorCodeName);
failedPortlets.getPortletHandles().add(portletContext.getPortletHandle());
}
}
}
//TODO: handle resourceLists better (should be using for things like errors)
ResourceList resourceList = null;
byte[] exportContextBytes = exportManager.encodeExportContextData(exportContext);
Lifetime lifetime = null;
if (exportContext.getCurrentTime() > 0)
{
lifetime = new Lifetime();
lifetime.setCurrentTime(toXMLGregorianCalendar(exportContext.getCurrentTime()));
lifetime.setTerminationTime(toXMLGregorianCalendar(exportContext.getTermintationTime()));
lifetime.setRefreshDuration(toDuration(exportContext.getRefreshDuration()));
}
return WSRPTypeFactory.createExportPortletsResponse(exportContextBytes, exportedPortlets, new ArrayList<FailedPortlets>(failedPortletsMap.values()), lifetime, resourceList);
}
catch (Exception e)
{
throw WSRP2ExceptionFactory.throwWSException(OperationFailed.class, "Operation Failed while trying to ExportPortlets.", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public ImportPortletsResponse importPortlets(ImportPortlets importPortlets) throws OperationFailed, InvalidRegistration, MissingParameters, ModifyRegistrationRequired
{
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(importPortlets, "ImportPortlets");
List<ImportPortlet> importPortletList = importPortlets.getImportPortlet();
if (!ParameterValidation.existsAndIsNotEmpty(importPortletList) || WSRPUtils.isSingletonListWithNullOrEmptyElement(importPortletList))
{
throw WSRP2ExceptionFactory.createWSException(MissingParameters.class, "Missing required list of portlets to import in ImportPortlets.", null);
}
Registration registration = producer.getRegistrationOrFailIfInvalid(importPortlets.getRegistrationContext());
// check if we have a valid userContext or not
UserContext userContext = importPortlets.getUserContext();
checkUserAuthorization(userContext);
try
{
RegistrationLocal.setRegistration(registration);
byte[] importContext = importPortlets.getImportContext();
Lifetime lifeTime = importPortlets.getLifetime();
List<ImportedPortlet> importedPortlets = new ArrayList<ImportedPortlet>();
Map<String, ImportPortletsFailed> failedPortletsMap = new HashMap<String, ImportPortletsFailed>();
ExportContext exportContext;
final ExportManager exportManager = producer.getExportManager();
try
{
exportContext = exportManager.createExportContext(importContext);
}
catch (Exception e)
{
throw WSRPExceptionFactory.createWSException(OperationFailed.class, "Invalid ImportContext.", e);
}
for (ImportPortlet importPortlet : importPortletList)
{
try
{
byte[] portletData = importPortlet.getExportData();
ExportPortletData exportPortletData;
if (lifeTime != null)
{
long currentTime = toLongDate(lifeTime.getCurrentTime());
long terminationTime = toLongDate(lifeTime.getTerminationTime());
long refreshDuration = lifeTime.getRefreshDuration().getTimeInMillis(lifeTime.getCurrentTime().toGregorianCalendar());
exportPortletData = exportManager.createExportPortletData(exportContext, currentTime, terminationTime, refreshDuration, portletData);
}
else
{
exportPortletData = exportManager.createExportPortletData(exportContext, -1, -1, -1, portletData);
}
String portletHandle = exportPortletData.getPortletHandle();
byte[] portletState = exportPortletData.getPortletState();
PortletContext pc = WSRPTypeFactory.createPortletContext(portletHandle, portletState);
org.gatein.pc.api.PortletContext pcPortletContext = WSRPUtils.convertToPortalPortletContext(pc);
org.gatein.pc.api.PortletContext cpc = producer.getPortletInvoker().importPortlet(PortletStateType.OPAQUE, pcPortletContext);
PortletContext wpc = WSRPUtils.convertToWSRPPortletContext(cpc);
ImportedPortlet importedPortlet = WSRPTypeFactory.createImportedPortlet(importPortlet.getImportID(), wpc);
importedPortlets.add(importedPortlet);
}
catch (Exception e)
{
if (log.isWarnEnabled())
{
log.warn("Error occured while trying to import a portlet.", e);
}
ErrorCodes.Codes errorCode;
String reason;
if (e instanceof NoSuchPortletException || e instanceof InvalidHandle)
{
errorCode = ErrorCodes.Codes.INVALIDHANDLE;
reason = "The specified portlet handle is invalid";
}
else if (e instanceof OperationFailed)
{
errorCode = ErrorCodes.Codes.OPERATIONFAILED;
reason = e.getMessage();
}
else if (e instanceof PortletInvokerException || e instanceof UnsupportedOperationException || e instanceof IllegalArgumentException)
{
errorCode = ErrorCodes.Codes.OPERATIONFAILED;
reason = "Error trying to create imported portlet.";
}
else // default error message.
{
errorCode = ErrorCodes.Codes.OPERATIONFAILED;
reason = "Error importing portlet.";
}
if (!failedPortletsMap.containsKey(errorCode.name()))
{
List<String> portleIDs = new ArrayList<String>();
portleIDs.add(importPortlet.getImportID());
ImportPortletsFailed failedPortlets = WSRPTypeFactory.createImportPortletsFailed(portleIDs, errorCode, reason);
failedPortletsMap.put(errorCode.name(), failedPortlets);
}
else
{
ImportPortletsFailed failedPortlets = failedPortletsMap.get(errorCode.name());
failedPortlets.getImportID().add(importPortlet.getImportID());
}
}
}
ResourceList resourceList = null; //TODO: figure out what exactly should be stored in the resource list here
return WSRPTypeFactory.createImportPortletsResponse(importedPortlets, new ArrayList<ImportPortletsFailed>(failedPortletsMap.values()), resourceList);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
public List<Extension> releaseExport(ReleaseExport releaseExport)
{
try
{
if (releaseExport != null && releaseExport.getExportContext() != null)
{
producer.getExportManager().releaseExport(releaseExport.getExportContext());
}
}
catch (Exception e)
{
if (log.isWarnEnabled())
{
log.warn("Error occured while trying to perform a ReleaseExport", e);
}
}
//this method shouldn't return anything
return WSRPTypeFactory.createReturnAny().getExtensions();
}
public Lifetime setExportLifetime(SetExportLifetime setExportLifetime) throws OperationFailed, InvalidRegistration, OperationNotSupported, ModifyRegistrationRequired
{
//this method is only valid if the producer can handle exporting by reference.
if (producer.getExportManager().getPersistenceManager() == null)
{
WSRP2ExceptionFactory.throwWSException(OperationNotSupported.class, "This producer does not support export by reference.", null);
}
WSRP2ExceptionFactory.throwOperationFailedIfValueIsMissing(setExportLifetime, "setExportLifetimePortlets");
byte[] exportContextBytes = setExportLifetime.getExportContext();
//NOTE: we can't throw a MissingParameterException since its not allowed as part of the spec
if (exportContextBytes == null)
{
WSRPExceptionFactory.throwWSException(OperationFailed.class, "Cannot call setExportLifetime with an empty ExportContext.", null);
}
Registration registration = producer.getRegistrationOrFailIfInvalid(setExportLifetime.getRegistrationContext());
// check if we have a valid userContext or not
UserContext userContext = setExportLifetime.getUserContext();
checkUserAuthorization(userContext);
try
{
RegistrationLocal.setRegistration(registration);
ExportContext exportContext;
long currentTime = toLongDate(setExportLifetime.getLifetime().getCurrentTime());
long terminationTime = toLongDate(setExportLifetime.getLifetime().getTerminationTime());
long refreshDuration = setExportLifetime.getLifetime().getRefreshDuration().getTimeInMillis(setExportLifetime.getLifetime().getCurrentTime().toGregorianCalendar());
exportContext = producer.getExportManager().setExportLifetime(exportContextBytes, currentTime, terminationTime, refreshDuration);
return getLifetime(exportContext);
}
catch (Exception e)
{
throw WSRPExceptionFactory.createWSException(OperationFailed.class, "Operation Failed while trying to setExportLifetime.", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
private void checkUserAuthorization(UserContext userContext)
{
//todo: implement
if (userContext != null)
{
}
}
private Portlet getPortletFrom(PortletContext portletContext, Registration registration) throws InvalidHandle
{
Portlet portlet;
try
{
RegistrationLocal.setRegistration(registration);
portlet = producer.getPortletInvoker().getPortlet(WSRPUtils.convertToPortalPortletContext(portletContext));
return portlet;
}
catch (PortletInvokerException e)
{
throw WSRP2ExceptionFactory.throwWSException(InvalidHandle.class, "Could not retrieve portlet '" + portletContext.getPortletHandle() + "'", e);
}
finally
{
RegistrationLocal.setRegistration(null);
}
}
//TODO: move these classes to the common module and write up proper lifetime utilities
private XMLGregorianCalendar toXMLGregorianCalendar(long time) throws DatatypeConfigurationException
{
Date date = new Date(time);
GregorianCalendar gregorianCalendar = new GregorianCalendar();
gregorianCalendar.setTime(date);
return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
}
private long toLongDate(XMLGregorianCalendar calendar)
{
return calendar.toGregorianCalendar().getTime().getTime();
}
private Duration toDuration(long duration) throws DatatypeConfigurationException
{
return DatatypeFactory.newInstance().newDuration(duration);
}
private Lifetime getLifetime(ExportContext exportContext) throws DatatypeConfigurationException
{
if (exportContext.getCurrentTime() >= 0)
{
Lifetime lifetime = new Lifetime();
XMLGregorianCalendar currentTime = toXMLGregorianCalendar(exportContext.getCurrentTime());
XMLGregorianCalendar terminationTime = toXMLGregorianCalendar(exportContext.getTermintationTime());
Duration duration = toDuration(exportContext.getRefreshDuration());
lifetime.setCurrentTime(currentTime);
lifetime.setTerminationTime(terminationTime);
lifetime.setRefreshDuration(duration);
return lifetime;
}
else
{
return null;
}
}
}