/** * Copyright (C) 2010-2017 Structr GmbH * * This file is part of Structr <http://structr.org>. * * Structr is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Structr 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Structr. If not, see <http://www.gnu.org/licenses/>. */ package org.structr.net; import java.util.LinkedHashSet; import java.util.Set; import org.structr.core.entity.AbstractSchemaNode; import org.structr.core.entity.SchemaNode; import org.structr.module.StructrModule; import org.structr.schema.action.Actions; public class PeerToPeerModule implements StructrModule { @Override public void onLoad() { } @Override public String getName() { return "peer-to-peer"; } @Override public Set<String> getDependencies() { return null; } @Override public Set<String> getFeatures() { return null; } @Override public void insertImportStatements(final AbstractSchemaNode schemaNode, final StringBuilder buf) { if (isShared(schemaNode)) { buf.append("import org.structr.net.SharedNodeInterface;\n"); } } @Override public Set<String> getInterfacesForType(final AbstractSchemaNode schemaNode) { final Set<String> interfaces = new LinkedHashSet<>(); if (isShared(schemaNode)) { interfaces.add("SharedNodeInterface"); } return interfaces; } @Override public void insertSaveAction(final AbstractSchemaNode schemaNode, final StringBuilder buf, final Actions.Type type) { if (isShared(schemaNode)) { switch (type) { case Create: buf.append("\n"); buf.append("\t\tfinal org.structr.net.PeerToPeerService service = getService();\n"); buf.append("\t\tif (service != null) {\n"); buf.append("\n"); buf.append("\t\t\tfinal org.structr.net.data.time.PseudoTime time = service.getTime();\n"); buf.append("\n"); buf.append("\t\t\tsuper.setProperty(lastModifiedPseudoTime, time.toString());\n"); buf.append("\t\t\tsuper.setProperty(createdPseudoTime, time.toString());\n"); buf.append("\t\t}\n"); buf.append("\n"); break; case Save: buf.append("\n"); buf.append("\t\tfinal org.structr.net.PeerToPeerService service = getService();\n"); buf.append("\t\tif (service != null) {\n"); buf.append("\n"); buf.append("\t\t\tservice.update(this);\n"); buf.append("\t\t}\n"); buf.append("\n"); break; default: break; } } } @Override public void insertSourceCode(final AbstractSchemaNode schemaNode, final StringBuilder buf) { if (isShared(schemaNode)) { buf.append("\tprivate boolean fullyCreated = false;\n"); buf.append("\n"); buf.append("\t@Override\n"); buf.append("\tpublic void onNodeInstantiation(final boolean isCreation) {\n"); buf.append("\t\tfullyCreated = !isCreation;\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tpublic Map<String, Object> getData() {\n"); buf.append("\n"); buf.append("\t\tfinal Set<PropertyKey> keys = new LinkedHashSet<>(StructrApp.getConfiguration().getPropertySet(entityType, \"shared\"));\n"); buf.append("\t\tfinal Map<String, Object> data = new HashMap<>();\n"); buf.append("\n"); buf.append("\t\tkeys.removeAll(nativeKeys);\n"); buf.append("\n"); buf.append("\t\tfor (final PropertyKey key : keys) {\n"); buf.append("\n"); buf.append("\t\t\tfinal PropertyConverter converter = key.inputConverter(securityContext);\n"); buf.append("\t\t\tObject value = convert(getProperty(key));\n"); buf.append("\n"); buf.append("\t\t\tif (converter != null && !(value instanceof String)) {\n"); buf.append("\n"); buf.append("\t\t\t\ttry {\n"); buf.append("\n"); buf.append("\t\t\t\t\tvalue = converter.revert(value);\n"); buf.append("\n"); buf.append("\t\t\t\t} catch (FrameworkException fex) {\n"); buf.append("\t\t\t\t\tfex.printStackTrace();\n"); buf.append("\t\t\t\t}\n"); buf.append("\t\t\t}\n"); buf.append("\n"); buf.append("\t\t\tdata.put(key.jsonName(), value);\n"); buf.append("\t\t}\n"); buf.append("\n"); buf.append("\t\treturn data;\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\t@Override\n"); buf.append("\tpublic void afterCreation(SecurityContext securityContext) {\n"); buf.append("\n"); buf.append("\t\tfullyCreated = true;\n"); buf.append("\n"); buf.append("\t\tfinal org.structr.net.PeerToPeerService service = getService();\n"); buf.append("\t\tif (service != null) {\n"); buf.append("\n"); buf.append("\t\t\tservice.create(this);\n"); buf.append("\t\t}\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\t@Override\n"); buf.append("\tpublic void afterDeletion(final SecurityContext securityContext, final PropertyMap properties) {\n"); buf.append("\n"); buf.append("\t\tfinal org.structr.net.PeerToPeerService service = getService();\n"); buf.append("\t\tif (service != null) {\n"); buf.append("\n"); buf.append("\t\t\tservice.delete(properties.get(GraphObject.id));\n"); buf.append("\t\t}\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\t@Override\n"); buf.append("\tpublic <T> Object setProperty(final PropertyKey<T> key, final T value) throws FrameworkException {\n"); buf.append("\n"); buf.append("\t\tif (fullyCreated) {\n"); buf.append("\n"); buf.append("\t\t\tfinal org.structr.net.PeerToPeerService service = getService();\n"); buf.append("\t\t\tif (service != null) {\n"); buf.append("\n"); buf.append("\t\t\t\tservice.setProperty(getProperty(GraphObject.id), key.jsonName(), convert(value));\n"); buf.append("\t\t\t}\n"); buf.append("\t\t}\n"); buf.append("\n"); buf.append("\t\treturn super.setProperty(key, value);\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tpublic org.structr.net.data.time.PseudoTime getCreationPseudoTime() {\n"); buf.append("\t\treturn org.structr.net.data.time.PseudoTime.fromString(getProperty(createdPseudoTime));\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tpublic org.structr.net.data.time.PseudoTime getLastModificationPseudoTime() {\n"); buf.append("\t\treturn org.structr.net.data.time.PseudoTime.fromString(getProperty(lastModifiedPseudoTime));\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tpublic void setProperty(final org.structr.core.app.App app, final PropertyKey key, final Object rawValue) throws FrameworkException {\n"); buf.append("\n"); buf.append("\t\tfinal PropertyConverter inputConverter = key.inputConverter(securityContext);\n"); buf.append("\t\tObject value = revert(app, rawValue);\n"); buf.append("\n"); buf.append("\t\tif (inputConverter != null) {\n"); buf.append("\t\t\tvalue = inputConverter.convert(value);\n"); buf.append("\t\t}\n"); buf.append("\n"); buf.append("\t\tsuper.setProperty(key, value);\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tpublic String getUserId() {\n"); buf.append("\n"); buf.append("\t\tfinal Principal owner = getOwnerNode();\n"); buf.append("\t\tif (owner != null) {\n"); buf.append("\n"); buf.append("\t\t\treturn owner.getName();\n"); buf.append("\t\t}\n"); buf.append("\n"); buf.append("\t\treturn Principal.SUPERUSER_ID;\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\t// ----- private methods -----\n"); buf.append("\tprivate org.structr.net.PeerToPeerService getService() {\n"); buf.append("\t\treturn Services.getInstance().getService(org.structr.net.PeerToPeerService.class);\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tprivate Object convert(final Object value) {\n"); buf.append("\n"); buf.append("\t\tObject result = value;\n"); buf.append("\n"); buf.append("\t\tif (value instanceof GraphObject) {\n"); buf.append("\n"); buf.append("\t\t\tresult = \"!\" + ((GraphObject)value).getUuid();\n"); buf.append("\n"); buf.append("\t\t} else if (value instanceof Collection) {\n"); buf.append("\n"); buf.append("\t\t\tfinal List<Object> list = new LinkedList<>();\n"); buf.append("\t\t\tfor (final Object item : ((Collection)value)) {\n"); buf.append("\n"); buf.append("\t\t\t\t// recurse\n"); buf.append("\t\t\t\tlist.add(convert(item));\n"); buf.append("\t\t\t}\n"); buf.append("\n"); buf.append("\t\t\tresult = \"#\" + StringUtils.join(list, \",\");\n"); buf.append("\t\t}\n"); buf.append("\n"); buf.append("\t\treturn result;\n"); buf.append("\t}\n"); buf.append("\n"); buf.append("\tprivate Object revert(final org.structr.core.app.App app, final Object value) throws FrameworkException {\n"); buf.append("\n"); buf.append("\t\tObject result = value;\n"); buf.append("\n"); buf.append("\t\tif (value instanceof String) {\n"); buf.append("\n"); buf.append("\t\t\tfinal String str = (String)value;\n"); buf.append("\n"); buf.append("\t\t\tif (str.startsWith(\"#\")) {\n"); buf.append("\n"); buf.append("\t\t\t\tif (str.length() > 1) {\n"); buf.append("\n"); buf.append("\t\t\t\t\tfinal String[] parts = str.substring(1).split(\"[,]+\");\n"); buf.append("\t\t\t\t\tfinal List<Object> list = new LinkedList<>();\n"); buf.append("\n"); buf.append("\t\t\t\t\tfor (final String part : parts) {\n"); buf.append("\t\t\t\t\t\tlist.add(revert(app, part));\n"); buf.append("\t\t\t\t\t}\n"); buf.append("\n"); buf.append("\t\t\t\t\tresult = list;\n"); buf.append("\n"); buf.append("\t\t\t\t} else {\n"); buf.append("\n"); buf.append("\t\t\t\t\tresult = Collections.emptyList();\n"); buf.append("\t\t\t\t}\n"); buf.append("\n"); buf.append("\t\t\t} else if (str.startsWith(\"!\") && str.length() == 33) {\n"); buf.append("\n"); buf.append("\t\t\t\tresult = app.get(str.substring(1));\n"); buf.append("\t\t\t}\n"); buf.append("\t\t}\n"); buf.append("\n"); buf.append("\t\treturn result;\n"); buf.append("\t}\n"); } } // ----- private methods ----- private boolean isShared(final AbstractSchemaNode schemaNode) { return Boolean.TRUE.equals(schemaNode.getProperty(SchemaNode.shared)); } }