use of org.structr.core.GraphObject in project structr by structr.
the class RestDataSource method getData.
// FIXME: this method is needed by the websocket search command because there is no reference node for the above method
public List<GraphObject> getData(final RenderContext renderContext, final String restQuery) throws FrameworkException {
final Map<Pattern, Class<? extends Resource>> resourceMap = new LinkedHashMap<>();
final SecurityContext securityContext = renderContext.getSecurityContext();
ResourceProvider resourceProvider = renderContext.getResourceProvider();
if (resourceProvider == null) {
try {
resourceProvider = UiResourceProvider.class.newInstance();
} catch (Throwable t) {
logger.error("Couldn't establish a resource provider", t);
return Collections.EMPTY_LIST;
}
}
// inject resources
resourceMap.putAll(resourceProvider.getResources());
Value<String> propertyView = new ThreadLocalPropertyView();
propertyView.set(securityContext, PropertyView.Ui);
HttpServletRequest request = securityContext.getRequest();
if (request == null) {
request = renderContext.getRequest();
}
// initialize variables
// mimic HTTP request
final HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(request) {
@Override
public Enumeration<String> getParameterNames() {
return new IteratorEnumeration(getParameterMap().keySet().iterator());
}
@Override
public String getParameter(final String key) {
String[] p = getParameterMap().get(key);
return p != null ? p[0] : null;
}
@Override
public String[] getParameterValues(final String key) {
return getParameterMap().get(key);
}
@Override
public Map<String, String[]> getParameterMap() {
String[] parts = StringUtils.split(getQueryString(), "&");
Map<String, String[]> parameterMap = new HashMap();
for (String p : parts) {
String[] kv = StringUtils.split(p, "=");
if (kv.length > 1) {
parameterMap.put(kv[0], new String[] { kv[1] });
}
}
return parameterMap;
}
@Override
public String getQueryString() {
return StringUtils.substringAfter(restQuery, "?");
}
@Override
public String getPathInfo() {
return StringUtils.substringBefore(restQuery, "?");
}
@Override
public StringBuffer getRequestURL() {
return new StringBuffer(restQuery);
}
};
// store original request
final HttpServletRequest origRequest = securityContext.getRequest();
// update request in security context
securityContext.setRequest(wrappedRequest);
// HttpServletResponse response = renderContext.getResponse();
Resource resource = null;
try {
resource = ResourceHelper.applyViewTransformation(wrappedRequest, securityContext, ResourceHelper.optimizeNestedResourceChain(securityContext, wrappedRequest, resourceMap, propertyView), propertyView);
} catch (IllegalPathException | NotFoundException e) {
logger.warn("Illegal path for REST query: {}", restQuery);
}
// reset request to old context
securityContext.setRequest(origRequest);
if (resource == null) {
return Collections.EMPTY_LIST;
}
// experimental: disable result count, prevents instantiation
// of large collections just for counting all the objects..
securityContext.ignoreResultCount(true);
// TODO: decide if we need to rest the REST request here
// securityContext.checkResourceAccess(request, resource.getResourceSignature(), resource.getGrant(request, response), PropertyView.Ui);
// add sorting & paging
String pageSizeParameter = wrappedRequest.getParameter(JsonRestServlet.REQUEST_PARAMETER_PAGE_SIZE);
String pageParameter = wrappedRequest.getParameter(JsonRestServlet.REQUEST_PARAMETER_PAGE_NUMBER);
String sortOrder = wrappedRequest.getParameter(JsonRestServlet.REQUEST_PARAMETER_SORT_ORDER);
String sortKeyName = wrappedRequest.getParameter(JsonRestServlet.REQUEST_PARAMETER_SORT_KEY);
boolean sortDescending = (sortOrder != null && "desc".equals(sortOrder.toLowerCase()));
int pageSize = parseInt(pageSizeParameter, NodeFactory.DEFAULT_PAGE_SIZE);
int page = parseInt(pageParameter, NodeFactory.DEFAULT_PAGE);
PropertyKey sortKey = null;
// set sort key
if (sortKeyName != null) {
Class<? extends GraphObject> type = resource.getEntityClass();
if (type == null) {
// fallback to default implementation
// if no type can be determined
type = AbstractNode.class;
}
sortKey = StructrApp.getConfiguration().getPropertyKeyForDatabaseName(type, sortKeyName, false);
}
// do action
Result result = Result.EMPTY_RESULT;
try {
result = resource.doGet(sortKey, sortDescending, pageSize, page);
} catch (NotFoundException nfe) {
logger.warn("No result from internal REST query: {}", restQuery);
}
result.setIsCollection(resource.isCollectionResource());
result.setIsPrimitiveArray(resource.isPrimitiveArray());
// Integer rawResultCount = (Integer) Services.getAttribute(NodeFactory.RAW_RESULT_COUNT + Thread.currentThread().getId());
PagingHelper.addPagingParameter(result, pageSize, page);
List<GraphObject> res = result.getResults();
renderContext.setResult(result);
return res != null ? res : Collections.EMPTY_LIST;
}
use of org.structr.core.GraphObject in project structr by structr.
the class XPathGraphDataSource method getData.
@Override
public Iterable<GraphObject> getData(final RenderContext renderContext, final DOMNode referenceNode) throws FrameworkException {
final String xpathQuery = referenceNode.getXpathQuery();
if (StringUtils.isBlank(xpathQuery)) {
return null;
}
final Document document = ((DOMNode) referenceNode).getOwnerDocument();
final XPathFactory factory = XPathFactory.newInstance();
final XPath xpath = factory.newXPath();
try {
// FIXME: this code works only with absolute xpath queries because
// the xpath parser implementation is stupid (comparing object
// equality using ==).
Object result = xpath.evaluate(xpathQuery, document, XPathConstants.NODESET);
List<GraphObject> results = new LinkedList<>();
if (result instanceof NodeList) {
NodeList nodes = (NodeList) result;
int len = nodes.getLength();
for (int i = 0; i < len; i++) {
Node node = nodes.item(i);
if (node instanceof GraphObject) {
results.add((GraphObject) node);
}
}
} else if (result instanceof GraphObject) {
results.add((GraphObject) result);
}
return results;
} catch (Throwable t) {
logger.warn("Unable to execute xpath query: {}", t.getMessage());
}
return Collections.EMPTY_LIST;
}
use of org.structr.core.GraphObject in project structr by structr.
the class IncludeFunction method apply.
@Override
public Object apply(final ActionContext ctx, final Object caller, final Object[] sources) throws FrameworkException {
try {
if (!(arrayHasMinLengthAndAllElementsNotNull(sources, 1) && sources[0] instanceof String)) {
return null;
}
final PropertyKey<DOMNode> sharedCompKey = StructrApp.key(DOMNode.class, "sharedComponent");
final SecurityContext securityContext = ctx.getSecurityContext();
final App app = StructrApp.getInstance(securityContext);
final RenderContext innerCtx = new RenderContext((RenderContext) ctx);
final List<DOMNode> nodeList = app.nodeQuery(DOMNode.class).andName((String) sources[0]).getAsList();
DOMNode node = null;
/**
* Nodes can be included via their name property These nodes MUST: 1. be unique in name 2. NOT be in the trash => have an ownerDocument AND a parent (public
* users are not allowed to see the __ShadowDocument__ ==> this check must either be made in a superuser-context OR the __ShadowDocument could be made public?)
*
* These nodes can be: 1. somewhere in the pages tree 2. in the shared components 3. both ==> causes a problem because we now have multiple nodes with the same
* name (one shared component and multiple linking instances of that component)
*
* INFOS:
*
* - If a DOMNode has "syncedNodes" it MUST BE a shared component - If a DOMNodes "sharedComponent" is set it MUST BE AN INSTANCE of a shared component => Can
* we safely ignore these? I THINK SO!
*/
for (final DOMNode n : nodeList) {
if (n.inTrash()) {
continue;
}
// IGNORE everything that REFERENCES a shared component!
if (n.getProperty(sharedCompKey) == null) {
// the DOMNode is either a shared component OR a named node in the pages tree
if (node == null) {
node = n;
} else {
// TODO: Do we need to remove the nodes from the nodeList which can be ignored? (references to a shared component)
return "Ambiguous node name \"" + ((String) sources[0]) + "\" (nodes found: " + StringUtils.join(nodeList, ", ") + ")";
}
}
}
if (node != null) {
if (sources.length == 3 && sources[1] instanceof Iterable && sources[2] instanceof String) {
final Iterable<GraphObject> iterable = FunctionDataSource.map((Iterable) sources[1]);
final String dataKey = (String) sources[2];
innerCtx.setListSource(iterable);
node.renderNodeList(securityContext, innerCtx, 0, dataKey);
} else {
node.render(innerCtx, 0);
}
if (innerCtx.appLibRendered()) {
((RenderContext) ctx).setAppLibRendered(true);
}
} else {
final File file = app.nodeQuery(File.class).andName((String) sources[0]).getFirst();
if (file != null) {
final String name = file.getProperty(NodeInterface.name);
final String contentType = file.getContentType();
final String charset = StringUtils.substringAfterLast(contentType, "charset=");
final String extension = StringUtils.substringAfterLast(name, ".");
if (contentType == null || StringUtils.isBlank(extension)) {
logger.warn("No valid file type detected. Please make sure {} has a valid content type set or file extension. Parameters: {}", new Object[] { name, getParametersAsString(sources) });
return "No valid file type detected. Please make sure " + name + " has a valid content type set or file extension.";
}
if (contentType.startsWith("text/css")) {
return "<link href=\"" + file.getPath() + "\" rel=\"stylesheet\">";
} else if (contentType.contains("/javascript")) {
return "<script src=\"" + file.getPath() + "\"></script>";
} else if (contentType.startsWith("image/svg")) {
try (final InputStream is = file.getInputStream()) {
final byte[] buffer = new byte[file.getSize().intValue()];
IOUtils.read(is, buffer);
return StringUtils.toEncodedString(buffer, Charset.forName(charset));
} catch (IOException ex) {
logger.warn("Exception for parameters: {}", getParametersAsString(sources));
logger.error("", ex);
}
return "<img alt=\"" + name + "\" src=\"" + file.getPath() + "\">";
} else if (contentType.startsWith("image/")) {
return "<img alt=\"" + name + "\" src=\"" + file.getPath() + "\">";
} else {
logger.warn("Don't know how to render content type or extension of {}. Parameters: {}", new Object[] { name, getParametersAsString(sources) });
return "Don't know how to render content type or extension of " + name + ".";
}
}
}
return StringUtils.join(innerCtx.getBuffer().getQueue(), "");
} catch (final IllegalArgumentException e) {
logParameterError(caller, sources, ctx.isJavaScriptContext());
return usage(ctx.isJavaScriptContext());
}
}
use of org.structr.core.GraphObject in project structr by structr.
the class DeserializationStrategy method setProperties.
protected void setProperties(final SecurityContext securityContext, final GraphObject obj, final PropertyMap properties) throws FrameworkException {
// are we allowed to set properties on related nodes?
final Boolean allowed = (Boolean) securityContext.getAttribute("setNestedProperties");
if (allowed != null && allowed == true) {
final PropertyMap mergedProperties = new PropertyMap();
for (final Entry<PropertyKey, Object> entry : properties.entrySet()) {
final PropertyKey key = entry.getKey();
final Object newValue = entry.getValue();
final Object oldValue = obj.getProperty(key);
if (newValue != null && !newValue.equals(oldValue)) {
mergedProperties.put(key, merge(oldValue, newValue));
}
}
obj.setProperties(securityContext, mergedProperties);
}
}
use of org.structr.core.GraphObject in project structr by structr.
the class IdDeserializationStrategy method deserialize.
@Override
public T deserialize(final SecurityContext securityContext, final Class<T> type, final S source, final Object context) throws FrameworkException {
final App app = StructrApp.getInstance(securityContext);
if (source != null) {
if (source instanceof Map) {
final Map<String, Object> properties = (Map<String, Object>) source;
Class<T> actualType = type;
if (actualType != null && actualType.isInterface()) {
// (creation wouldn't work otherwise anyway)
if (properties.containsKey(NodeInterface.type.jsonName())) {
final String typeFromInput = properties.get(NodeInterface.type.jsonName()).toString();
actualType = StructrApp.getConfiguration().getNodeEntityClass(typeFromInput);
// reset type on failed check
if (actualType == null) {
actualType = type;
}
}
}
final PropertyMap convertedProperties = PropertyMap.inputTypeToJavaType(securityContext, actualType, properties);
final Set<PropertyKey> allProperties = StructrApp.getConfiguration().getPropertySet(type, "all");
final Map<String, Object> foreignProps = new HashMap<>();
T relatedNode = null;
// If property map contains the uuid, search only for uuid
if (convertedProperties.containsKey(GraphObject.id)) {
relatedNode = (T) app.getNodeById(convertedProperties.get(GraphObject.id));
if (relatedNode != null) {
if (!SearchCommand.isTypeAssignableFromOtherType(type, relatedNode.getClass())) {
throw new FrameworkException(422, "Node type mismatch", new TypeToken(type.getSimpleName(), null, type.getSimpleName()));
}
for (final PropertyKey key : convertedProperties.keySet()) {
if (!key.isUnique() && !key.isCompound() && !isIdentifying(actualType, key) && !allProperties.contains(key)) {
// store "foreign" properties (those that are to be set on the newly created relationship
foreignProps.put(key.jsonName(), properties.get(key.jsonName()));
}
}
// node found, remove UUID
convertedProperties.remove(GraphObject.id);
}
} else {
final PropertyMap uniqueKeyValues = new PropertyMap();
for (final PropertyKey key : convertedProperties.keySet()) {
if (key.isUnique() || key.isCompound() || isIdentifying(actualType, key)) {
uniqueKeyValues.put(key, convertedProperties.get(key));
} else if (!allProperties.contains(key)) {
// store "foreign" properties (those that are to be set on the newly created relationship
foreignProps.put(key.jsonName(), properties.get(key.jsonName()));
}
}
// (this is quite similar to the Cypher MERGE command),
if (!uniqueKeyValues.isEmpty()) {
final List<T> possibleResults = app.nodeQuery(type).and(uniqueKeyValues).getAsList();
final int num = possibleResults.size();
switch(num) {
case 0:
// not found => will be created
break;
case 1:
relatedNode = possibleResults.get(0);
break;
default:
// more than one => not unique??
throw new FrameworkException(422, concat("Unable to resolve related node of type ", type.getSimpleName(), ", ambiguous result: found ", num, " nodes for the given property set."));
}
} else {
// throw exception here?
}
}
if (relatedNode == null) {
// no related node found, should we create one?
if (relationProperty != null) {
final Relation relation = relationProperty.getRelation();
if (relationProperty.doAutocreate()) {
return app.create(type, convertedProperties);
} else {
throw new FrameworkException(422, concat("Cannot create ", relation.getOtherType(type).getSimpleName(), ": no matching ", type.getSimpleName(), " found for the given property set ", convertedProperties, " and autoCreate has a value of ", relationProperty.getAutocreateFlagName()));
}
}
// FIXME: when can the relationProperty be null at all?
throw new FrameworkException(500, concat("Unable to resolve related node of type ", type.getSimpleName(), ", no relation defined."));
} else {
// set properties on related node?
if (!convertedProperties.isEmpty()) {
setProperties(securityContext, relatedNode, convertedProperties);
}
if (foreignProps.isEmpty()) {
return relatedNode;
} else {
return (T) new EntityAndPropertiesContainer(relatedNode, foreignProps);
}
}
} else if (type.isAssignableFrom(source.getClass())) {
return (T) source;
} else {
// interpret source as a raw ID string and fetch entity
final GraphObject obj = app.getNodeById(source.toString());
if (obj != null && !type.isAssignableFrom(obj.getClass())) {
throw new FrameworkException(422, "Node type mismatch", new TypeToken(obj.getClass().getSimpleName(), null, type.getSimpleName()));
}
return (T) obj;
}
}
return null;
}
Aggregations