/*
* Copyright (c) 2009-2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.restlets;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eurekastreams.server.domain.GadgetDefinition;
import org.eurekastreams.server.domain.GeneralGadgetDefinition;
import org.eurekastreams.server.domain.gadgetspec.EnumValuePairDTO;
import org.eurekastreams.server.domain.gadgetspec.GadgetMetaDataDTO;
import org.eurekastreams.server.domain.gadgetspec.UserPrefDTO;
import org.eurekastreams.server.domain.gadgetspec.UserPrefDTO.DataType;
import org.eurekastreams.server.persistence.GadgetMapper;
import org.eurekastreams.server.service.opensocial.gadgets.spec.GadgetMetaDataFetcher;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Status;
import org.restlet.resource.Representation;
import org.restlet.resource.ResourceException;
import org.restlet.resource.StringRepresentation;
import org.restlet.resource.Variant;
/**
* This class provides the Restlet implementation for creating
* user preferences form ui for an OpenSocial gadget.
*
*/
public class UserPrefsFormUIResource extends SmpResource
{
/**
* Local logger instance.
*/
private static Log logger = LogFactory.getLog(UserPrefsFormUIResource.class);
/**
* Key for retrieving the Gadget Id from the rest url.
*/
private static final String MODULE_ID_KEY = "moduleid";
/**
* Key for retrieving the Gadget Definition Url from the rest url.
*/
private static final String GADGET_DEF_URL_KEY = "url";
/**
* Key for retrieving the saved user preferences.
*/
private static final String SAVED_USER_PREFS = "saveduserprefs";
/**
* Error message when user preferences cannot be retrieved.
*/
private static final String USER_PREFS_ERROR_MESSAGE =
"Error occurred retrieving preferences for this gadget.";
/**
* Default format for encoding/decoding url's retrieved in parameters.
*/
private static final String DEFAULT_URL_ENCODING = "UTF-8";
/**
* Local storage for the module Id of the calling gadget.
*/
private Long moduleId;
/**
* List of user preferences retrieved from the url passed in.
*/
private Map<String, String> savedUserPrefs;
/**
* Local instance of the gadget mapper.
*/
private GadgetMapper gadgetMapper;
/**
* Local instance of the gadget metadata fetcher.
*/
private GadgetMetaDataFetcher gadgetMetaFetcher;
/**
* URI for the gadget definition to retrieve user preferences for.
*/
private String gadgetDefUrl;
/**
* Initialize the parameters for the request.
* attributes handled:
* moduleId - refers to the gadget instance id (not to be confused with the
* application id.
* url - gadget definition url target to generate preferences script for.
* saveduserprefs - querystring formatted (and url encoded) collection of
* key value pairs representing the currently saved user settings. This
* data is important for generating prepopulated inputs.
* @param request - current request information.
*/
@Override
protected void initParams(final Request request)
{
//Retrieve the module id and gadget def url for the
//metadata request.
if (request.getAttributes().containsKey(MODULE_ID_KEY)
&& request.getAttributes().containsKey(GADGET_DEF_URL_KEY))
{
try
{
URI tempGadgetDefURI = new URI(
(String) request.getAttributes().get(GADGET_DEF_URL_KEY));
gadgetDefUrl = URLDecoder.decode(
tempGadgetDefURI.toString(), DEFAULT_URL_ENCODING);
String tempAppId = (String) request.getAttributes().get(MODULE_ID_KEY);
logger.debug("Retreived moduleId from querystring: " + tempAppId);
moduleId = Long.parseLong(tempAppId.trim());
}
catch (Exception ex)
{
logger.error("Error occurred retrieving the module id from "
+ "the request, defaulting to 0 " + ex);
moduleId = 0L;
}
}
//Saved User Preferences are optional and thus pulled off the request seperately.
savedUserPrefs = new HashMap<String, String>();
if (request.getAttributes().containsKey(SAVED_USER_PREFS))
{
String urlUserPreferences = (String) request.getAttributes().get(SAVED_USER_PREFS);
List<String> tempUserPrefsList = new ArrayList<String>(
Arrays.asList(urlUserPreferences.split("&")));
for (String userPref : tempUserPrefsList)
{
if ((userPref.trim().length() > 3)
&& userPref.trim().contains("="))
{
try
{
String[] userPrefBreakdown = userPref.split("=");
savedUserPrefs.put(
URLDecoder.decode(userPrefBreakdown[0], DEFAULT_URL_ENCODING),
URLDecoder.decode(userPrefBreakdown[1], DEFAULT_URL_ENCODING));
}
catch (Exception ex)
{
logger.error("Error occurred retrieving the user "
+ "preferences from the url string for: " + userPref);
}
}
}
}
}
/**
* This method injects the gadget mapper.
*
* @param inGadgetMapper
* mapper.
*/
public void setGadgetMapper(
final GadgetMapper inGadgetMapper)
{
gadgetMapper = inGadgetMapper;
}
/**
* This method injects the gadget metadata fetcher.
* @param inGadgetMetaFetcher - instance of GadgetMetaFetcher to set locally.
*/
public void setGadgetMetaDataFetcher(
final GadgetMetaDataFetcher inGadgetMetaFetcher)
{
gadgetMetaFetcher = inGadgetMetaFetcher;
}
/**
* Provide the settings output for the gadget definitions supplied.
* @param variant - context.
* @return Representation of the response.
*
* @throws ResourceException when an error is encountered with the representation
* code.
*/
@Override
public Representation represent(final Variant variant) throws ResourceException
{
//retrieve gadget metadata with preferences from shindig.
//assembly script based on types and number of preferences.
if (moduleId != null && moduleId > 0
&& gadgetDefUrl != null)
{
StringBuilder sb = new StringBuilder();
try
{
Map<String, GeneralGadgetDefinition> gadgetDefs = new HashMap<String, GeneralGadgetDefinition>();
GadgetDefinition targetGadgetDef = gadgetMapper.findById(moduleId).getGadgetDefinition();
gadgetDefs.put(gadgetDefUrl, targetGadgetDef);
List<GadgetMetaDataDTO> gadgetMetaData = gadgetMetaFetcher.getGadgetsMetaData(gadgetDefs);
for (GadgetMetaDataDTO currentGMeta : gadgetMetaData)
{
logger.debug("Retrieved Metadata for Gadget" + targetGadgetDef.getId()
+ " Author: " + currentGMeta.getAuthor()
+ " UserPrefsSize: " + currentGMeta.getUserPrefs().size());
sb.append(buildUserPreferencesUI(currentGMeta));
}
}
catch (Exception ex)
{
logger.error("Error occurred retrieving User Preferences script", ex);
sb.append("var htmlString_" + moduleId + "='';");
sb.append("htmlString_" + moduleId + " += '<div class=\"gadget-preferences\">"
+ USER_PREFS_ERROR_MESSAGE + "</div>';");
sb.append("gadget_callback_" + moduleId + "(htmlString_" + moduleId + ");");
}
logger.debug("Returning the edit settings script: " + sb.toString());
Representation rep = new StringRepresentation(sb.toString(), MediaType.APPLICATION_JAVASCRIPT);
rep.setExpirationDate(new Date());
return rep;
}
else
{
throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Invalid application id passed to endpoint");
}
}
/**
* This method constructs the user preferences for the gadget MetaData supplied.
* @param gadgetMetaData - GadgetMetaDataDTO object that contains the info for
* retrieving the User Preferences ui.
* @return - string representation of the user preferences ui.
*/
private String buildUserPreferencesUI(final GadgetMetaDataDTO gadgetMetaData)
{
StringBuilder sbUp = new StringBuilder();
StringBuilder sbHtml = new StringBuilder();
int userPrefIndex = 0;
String userPrefPrefix = "m_" + moduleId;
sbUp.append("var htmlString_" + moduleId + "=\"\";");
sbHtml.append("<div style=\"display:none\" class=\"gadget-preferences\">");
for (UserPrefDTO currentUserPref : gadgetMetaData.getUserPrefs())
{
//If the value has already been saved, use the saved value.
if (savedUserPrefs.size() > 0
&& savedUserPrefs.containsKey("up_" + currentUserPref.getName()))
{
currentUserPref.setDefaultValue(savedUserPrefs.get("up_" + currentUserPref.getName()));
}
sbHtml.append("<div class=\"input-area\">");
if (currentUserPref.getDataType().name() != DataType.HIDDEN.name())
{
sbHtml.append("<div class=\"label-area\"><label class=\"label\">");
sbHtml.append(currentUserPref.getDisplayName() + "</label></div>");
sbHtml.append("<div class=\"input-box\">");
}
if (currentUserPref.getDataType().name() == DataType.HIDDEN.name())
{
sbHtml.append("<input type=\"hidden\" id=\"" + userPrefPrefix + "_" + userPrefIndex + "\" ");
sbHtml.append("name=\"" + userPrefPrefix + "_up_" + currentUserPref.getName() + "\" ");
sbHtml.append("value=\"" + StringEscapeUtils.escapeHtml(currentUserPref.getDefaultValue()) + "\"/>");
}
else if (currentUserPref.getDataType().name() == DataType.ENUM.name())
{
sbHtml.append("<select class=\"drop-down\" id=\"" + userPrefPrefix + "_" + userPrefIndex + "\" ");
sbHtml.append("name=\"" + userPrefPrefix + "_up_" + currentUserPref.getName() + "\">");
for (EnumValuePairDTO currentEnumValue : currentUserPref.getOrderedEnumValues())
{
sbHtml.append("<option value=\"" + currentEnumValue.getValue() + "\" ");
if (currentUserPref.getDefaultValue().equals(currentEnumValue.getValue()))
{
sbHtml.append("selected ");
}
sbHtml.append(">" + currentEnumValue.getDisplayValue() + "</option>");
}
sbHtml.append("</select>");
sbHtml.append("</div>");
}
else if (currentUserPref.getDataType().name() == DataType.LIST.name())
{
//TODO: handle list here with a bunch of checkboxes.
logger.info("Handle user preferences type List");
}
else if (currentUserPref.getDataType().name() == DataType.BOOL.name())
{
sbHtml.append("<input type=\"checkbox\" class=\"checkbox\" id=\""
+ userPrefPrefix + "_" + userPrefIndex + "\" ");
sbHtml.append("name=\""
+ userPrefPrefix + "_up_" + currentUserPref.getName() + "\" ");
try
{
if (Boolean.parseBoolean(currentUserPref.getDefaultValue())
|| Integer.parseInt(currentUserPref.getDefaultValue()) > 0)
{
sbHtml.append("checked ");
}
}
catch (NumberFormatException nex)
{
logger.info("Data passed in for boolean user preference"
+ "was not correct string or number format, assuming false.");
}
sbHtml.append("value=\"true\" onClick=\"document.getElementById(\\'"
+ userPrefPrefix + "_" + userPrefIndex + "\\').value = "
+ "(this.checked ? \\'1\\' : \\'0\\')\"/>");
sbHtml.append("</div>");
}
else
{
sbHtml.append("<input type=\"text\" class=\"text-box\" id=\""
+ userPrefPrefix + "_" + userPrefIndex + "\" ");
sbHtml.append("name=\""
+ userPrefPrefix + "_up_" + currentUserPref.getName() + "\" ");
sbHtml.append("value=\""
+ StringEscapeUtils.escapeHtml(currentUserPref.getDefaultValue().replace("'", "\\'")) + "\"/>");
sbHtml.append("</div>");
}
if (currentUserPref.getRequired())
{
sbHtml.append("<div>Required</div>");
}
//End Input area only when not a hidden input.
if (currentUserPref.getDataType().name() != DataType.HIDDEN.name())
{
sbHtml.append("</div>");
}
userPrefIndex++;
}
sbHtml.append("</div>");
sbHtml.append("<input type=\"hidden\" id=\"" + userPrefPrefix + "_numfields\" ");
sbHtml.append("value=\"" + gadgetMetaData.getUserPrefs().size() + "\"/>");
sbHtml.append("</div>");
sbUp.append("htmlString_" + moduleId + "+='" + sbHtml.toString() + "';");
sbUp.append("gadget_callback_" + moduleId + "(unescape(htmlString_" + moduleId + "));");
return sbUp.toString();
}
}