/*
* Copyright (c) 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.actions.strategies.galleryitem;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eurekastreams.commons.exceptions.ValidationException;
import org.eurekastreams.server.domain.GeneralGadgetDefinition;
import org.eurekastreams.server.domain.gadgetspec.GadgetMetaDataDTO;
import org.eurekastreams.server.domain.gadgetspec.UserPrefDTO;
import org.eurekastreams.server.domain.stream.BaseObjectType;
import org.eurekastreams.server.domain.stream.plugins.PluginDefinition;
import org.eurekastreams.server.service.opensocial.gadgets.spec.GadgetMetaDataFetcher;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* populates a plugin.
*
*/
public class PluginDefinitionPopulator implements GalleryItemPopulator<PluginDefinition>
{
/**
* Error if object type is not recognized.
*/
static final String OBJECTTYPE_ERROR = "Unrecognized ObjectType. ";
/**
* Error message if UpdateFrequency is of an invalid value.
*/
static final String UPDATE_FREQUENCY_ERROR = "UpdateFrequency is not a valid value. ";
/**
* Error message if required feature is not present.
*/
static final String FEATURE_ERROR = "Required plugin feature not present. ";
/**
* Error message if plugin url is not valid.
*/
static final String CANT_FIND_PLUGIN = "Plugin could not be located at that url. ";
/**
* Logger.
*/
private Log log = LogFactory.getLog(PluginDefinitionPopulator.class);
/**
* Meta data fetcher.
*/
private GadgetMetaDataFetcher metaDataFetcher = null;
/**
* the data to enter if nothing is given.
*/
private Long defaultUpdateFrequency;
/**
* the data to enter if nothing is given.
*/
private BaseObjectType defaultObjectType;
/**
* Constructor.
*
* @param inMetaDataFetcher
* meta data fetcher.
* @param inDefaultUpdateFrequency
* the default value if it is not in the plugin.
* @param inDefaultObjectType
* the default value if it is not in the plugin.
*/
public PluginDefinitionPopulator(final GadgetMetaDataFetcher inMetaDataFetcher,
final Long inDefaultUpdateFrequency, final BaseObjectType inDefaultObjectType)
{
metaDataFetcher = inMetaDataFetcher;
defaultUpdateFrequency = inDefaultUpdateFrequency;
defaultObjectType = inDefaultObjectType;
}
/**
* Populates a plugin definition.
*
* @param inPluginDefinition
* the plugin definition to populate
* @param inPluginDefinitionUrl
* the plugin definition url.
*/
@Override
public void populate(final PluginDefinition inPluginDefinition,
final String inPluginDefinitionUrl)
{
boolean hasFeature = false;
ValidationException ve = new ValidationException();
String errorMessage = "";
// ensure the gadget is a plugin type.
try
{
hasFeature = checkForRequiredFeature(inPluginDefinitionUrl);
}
catch (Exception ex)
{
log.debug(CANT_FIND_PLUGIN, ex);
ve.addError("url", CANT_FIND_PLUGIN);
throw ve;
}
final Map<String, GeneralGadgetDefinition> gadgetDefs = new HashMap<String, GeneralGadgetDefinition>();
gadgetDefs.put(inPluginDefinitionUrl, inPluginDefinition);
log.info("Fetching gadget data");
try
{
List<GadgetMetaDataDTO> meta = metaDataFetcher.getGadgetsMetaData(gadgetDefs);
if (meta.size() > 0)
{
/*
* These two fields are the only fields being populated because the other values are populate via
* Shindig on each ui request.
*/
GadgetMetaDataDTO metadata = meta.get(0);
for (UserPrefDTO up : metadata.getUserPrefs())
{
if ("updateFrequency".equals(up.getName()))
{
try
{
Long updateFreq = Long.parseLong(up.getDefaultValue());
inPluginDefinition.setUpdateFrequency(updateFreq);
}
catch (Exception ex)
{
errorMessage += UPDATE_FREQUENCY_ERROR;
}
}
else if ("objectType".equals(up.getName()))
{
try
{
inPluginDefinition.setObjectType(BaseObjectType.valueOf(up.getDefaultValue()));
}
catch (Exception ex)
{
errorMessage += OBJECTTYPE_ERROR;
}
}
}
}
// Check for all required elements
if (!hasFeature)
{
errorMessage += FEATURE_ERROR;
}
// add see if a error message was created. If so add it as a validation exceptions. If not check for
// defaults.
if (!errorMessage.equals(""))
{
ve.addError("url", errorMessage);
}
else
{
if (inPluginDefinition.getObjectType() == null)
{
inPluginDefinition.setObjectType(defaultObjectType);
}
if (inPluginDefinition.getUpdateFrequency() == null)
{
inPluginDefinition.setUpdateFrequency(defaultUpdateFrequency);
}
}
// Check if any errors exist
if (!ve.getErrors().isEmpty())
{
throw ve;
}
}
catch (ValidationException ve2)
{
throw ve2;
}
catch (Exception ex)
{
ve.addError("url", "Error retreiving plugin data.");
log.debug(ex.fillInStackTrace());
throw ve;
}
}
/**
* Checks for the required plugin feature before updating the plugin def.
*
* @param inPluginDefinitionUrl
* The url to the plugin definition.
* @return true if the feature is found and false if not found.
* @throws XPathExpressionException
* not expected.
* @throws ParserConfigurationException
* not expected.
* @throws SAXException
* not expected.
* @throws IOException
* expected if the url is invalid.
*/
private boolean checkForRequiredFeature(final String inPluginDefinitionUrl) throws XPathExpressionException,
ParserConfigurationException, SAXException, IOException
{
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(inPluginDefinitionUrl);
XPath xpath = XPathFactory.newInstance().newXPath();
// this is used to get the amount of required feature we need to check.
XPathExpression getFeatureAmountExpr = xpath.compile("//Module/ModulePrefs/Require");
NodeList nodeResults = (NodeList) getFeatureAmountExpr.evaluate(doc, XPathConstants.NODESET);
for (int i = 1; i <= nodeResults.getLength(); i++)
{
XPathExpression getFeatureExpr = xpath.compile("//Module/ModulePrefs/Require[" + i + "]/@feature");
String thing = (String) getFeatureExpr.evaluate(doc, XPathConstants.STRING);
if (thing.equals("eurekastreams-streamplugin"))
{
return true;
}
}
return false;
}
}