org.apache.shindig.gadgets.spec.PipelinedData Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shindig-gadgets Show documentation
Show all versions of shindig-gadgets Show documentation
Renders gadgets, provides the gadget metadata service, and serves
all javascript required by the OpenSocial specification.
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.shindig.gadgets.spec;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.xml.XmlException;
import org.apache.shindig.expressions.Expressions;
import org.apache.shindig.gadgets.AuthType;
import org.apache.shindig.gadgets.variables.Substitutions;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.ValueExpression;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Parsing code for <os:*> elements.
*/
public class PipelinedData {
private boolean needsViewer;
private boolean needsOwner;
private Map allPreloads;
public static final String OPENSOCIAL_NAMESPACE = "http://ns.opensocial.org/2008/markup";
public static final String EXTENSION_NAMESPACE = "http://ns.opensocial.org/2009/extensions";
public PipelinedData(Element element, Uri base) throws SpecParserException {
Map allPreloads = Maps.newHashMap();
// TODO: extract this loop into XmlUtils.getChildrenWithNamespace
for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
if (!(node instanceof Element)) {
continue;
}
Element child = (Element) node;
if (EXTENSION_NAMESPACE.equals(child.getNamespaceURI())) {
if ("Variable".equals(child.getLocalName())) {
allPreloads.put(child.getAttribute("key"), createVariableRequest(child));
}
} else if (OPENSOCIAL_NAMESPACE.equals(child.getNamespaceURI())) {
String elementName = child.getLocalName();
String key = child.getAttribute("key");
if (key == null) {
throw new SpecParserException("Missing key attribute on os:" + elementName);
}
try {
if ("PeopleRequest".equals(elementName)) {
allPreloads.put(key, createPeopleRequest(child));
} else if ("ViewerRequest".equals(elementName)) {
allPreloads.put(key, createViewerRequest(child));
} else if ("OwnerRequest".equals(elementName)) {
allPreloads.put(key, createOwnerRequest(child));
} else if ("PersonAppDataRequest".equals(elementName)) {
// TODO: delete when 0.9 app data retrieval is supported
allPreloads.put(key, createPersonAppDataRequest(child));
} else if ("ActivitiesRequest".equals(elementName)) {
allPreloads.put(key, createActivityRequest(child));
} else if ("ActivityStreamsRequest".equals(elementName)) {
allPreloads.put(key, createActivityStreamRequest(child));
} else if ("DataRequest".equals(elementName)) {
allPreloads.put(key, createDataRequest(child));
} else if ("HttpRequest".equals(elementName)) {
allPreloads.put(key, createHttpRequest(child, base));
} else {
// TODO: This is wrong - the spec should parse, but should preload
// notImplemented
throw new SpecParserException("Unknown element ');
}
} catch (ELException ele) {
throw new SpecParserException(new XmlException(ele));
}
}
}
this.allPreloads = Collections.unmodifiableMap(allPreloads);
}
private BatchItemData createVariableRequest(Element child) {
return new VariableData(child.getAttribute("value"));
}
private PipelinedData(PipelinedData socialData, Substitutions substituter) {
Map allPreloads = Maps.newHashMap();
for (Map.Entry preload : socialData.allPreloads.entrySet()) {
allPreloads.put(preload.getKey(), preload.getValue().substitute(substituter));
}
this.allPreloads = Collections.unmodifiableMap(allPreloads);
}
/**
* Allows the creation of a view from an existing view so that localization
* can be performed.
*/
public PipelinedData substitute(Substitutions substituter) {
return new PipelinedData(this, substituter);
}
public interface Batch {
Map getPreloads();
Batch getNextBatch(ELResolver rootObjects);
}
/** Temporary type until BatchItem is made fully polymorphic */
public enum BatchType {
SOCIAL,
HTTP,
VARIABLE
}
/** Item within a batch */
public interface BatchItem {
BatchType getType();
Object getData();
}
/** Shared data used to generate BatchItems */
interface BatchItemData {
BatchItem evaluate(Expressions expressions, ELContext elContext);
BatchItemData substitute(Substitutions substituter);
}
/**
* Gets the first batch of preload requests. Preloads that require root
* objects not yet available will not be executed in this batch, but may
* become available in subsequent batches.
*
* @param rootObjects an ELResolver that can evaluate currently available
* root objects.
* @see org.apache.shindig.gadgets.GadgetELResolver
* @return a batch, or null if no batch could be created
*/
public Batch getBatch(Expressions expressions, ELResolver rootObjects) {
return getBatch(expressions, rootObjects, allPreloads);
}
/**
* Create a Batch of preload requests
* @param expressions expressions instance for parsing expressions
* @param rootObjects an ELResolver that can evaluate currently available
* root objects.
* @param currentPreloads the remaining social/http preloads
*/
private Batch getBatch(Expressions expressions, ELResolver rootObjects,
Map currentPreloads) {
ELContext elContext = expressions.newELContext(rootObjects);
Map evaluatedPreloads = Maps.newHashMap();
Map pendingPreloads = null;
if (currentPreloads != null) {
for (Map.Entry preload : currentPreloads.entrySet()) {
try {
BatchItem value = preload.getValue().evaluate(expressions, elContext);
evaluatedPreloads.put(preload.getKey(), value);
} catch (PropertyNotFoundException pe) {
// Property-not-found: presume that this is because a top-level
// variable isn't available yet, which means that this needs to be
// postponed to the next batch.
if (pendingPreloads == null) {
pendingPreloads = Maps.newHashMap();
}
pendingPreloads.put(preload.getKey(), preload.getValue());
} catch (ELException e) {
// TODO: Handle!?!
throw new RuntimeException(e);
}
}
}
// Nothing evaluated or pending; return null for the batch. Note that
// there may be multiple PipelinedData objects (e.g., from multiple
//