use of org.structr.core.app.App in project structr by structr.
the class SchemaHelper method getSource.
public static String getSource(final AbstractSchemaNode schemaNode, final ErrorBuffer errorBuffer) throws FrameworkException {
final Collection<StructrModule> modules = StructrApp.getConfiguration().getModules().values();
final App app = StructrApp.getInstance();
final Map<String, List<ActionEntry>> methods = new LinkedHashMap<>();
final Map<String, Set<String>> viewProperties = new LinkedHashMap<>();
final List<String> propertyValidators = new LinkedList<>();
final Set<String> existingPropertyNames = new LinkedHashSet<>();
final Set<String> compoundIndexKeys = new LinkedHashSet<>();
final Set<String> propertyNames = new LinkedHashSet<>();
final Set<String> relationshipPropertyNames = new LinkedHashSet<>();
final Set<Validator> validators = new LinkedHashSet<>();
final Set<String> implementedInterfaces = new LinkedHashSet<>();
final List<String> importStatements = new LinkedList<>();
final Set<String> enums = new LinkedHashSet<>();
final StringBuilder src = new StringBuilder();
final StringBuilder mixinCodeBuffer = new StringBuilder();
final Class baseType = AbstractNode.class;
final String _className = schemaNode.getProperty(SchemaNode.name);
final String _extendsClass = schemaNode.getProperty(SchemaNode.extendsClass);
final String superClass = _extendsClass != null ? _extendsClass : baseType.getSimpleName();
final boolean extendsAbstractNode = _extendsClass == null;
// check superclass
if (!extendsAbstractNode && !superClass.startsWith("org.structr.dynamic.") && !SchemaHelper.hasType(superClass)) {
// we can only detect if a type is missing that is usually provided by a module; we
// can not detect whether a dynamic type is missing because those are only available
// after compiling the whole set of schema nodes
logger.warn("Dynamic type {} cannot be used, superclass {} not defined.", schemaNode.getName(), superClass);
return null;
}
// import mixins, check that all types exist and return null otherwise (causing this class to be ignored)
SchemaHelper.collectInterfaces(schemaNode, implementedInterfaces);
// package name
src.append("package org.structr.dynamic;\n\n");
// include import statements from mixins
SchemaHelper.formatImportStatements(schemaNode, src, baseType, importStatements);
if (schemaNode.getProperty(SchemaNode.isInterface)) {
// create interface
src.append("public interface ");
src.append(_className);
// output implemented interfaces
if (!implementedInterfaces.isEmpty()) {
src.append(" extends ");
src.append(StringUtils.join(implementedInterfaces, ", "));
}
} else {
// create class
src.append("public ");
if (schemaNode.getProperty(SchemaNode.isAbstract)) {
src.append("abstract ");
}
src.append("class ");
src.append(_className);
src.append(" extends ");
src.append(superClass);
// output implemented interfaces
if (!implementedInterfaces.isEmpty()) {
src.append(" implements ");
src.append(StringUtils.join(implementedInterfaces, ", "));
}
}
src.append(" {\n\n");
// output related node definitions, collect property views
for (final SchemaRelationshipNode outRel : schemaNode.getProperty(SchemaNode.relatedTo)) {
final String propertyName = outRel.getPropertyName(_className, existingPropertyNames, true);
propertyNames.add(propertyName);
src.append(outRel.getPropertySource(propertyName, true));
// schema changes are expected to be added to "ui" view.
if (!outRel.getProperty(SchemaRelationshipNode.isPartOfBuiltInSchema)) {
addPropertyToView(PropertyView.Ui, propertyName, viewProperties);
}
relationshipPropertyNames.add(propertyName);
}
// output related node definitions, collect property views
for (final SchemaRelationshipNode inRel : schemaNode.getProperty(SchemaNode.relatedFrom)) {
final String propertyName = inRel.getPropertyName(_className, existingPropertyNames, false);
propertyNames.add(propertyName);
src.append(inRel.getPropertySource(propertyName, false));
// schema changes are expected to be added to "ui" view.
if (!inRel.getProperty(SchemaRelationshipNode.isPartOfBuiltInSchema)) {
SchemaHelper.addPropertyToView(PropertyView.Ui, propertyName, viewProperties);
}
relationshipPropertyNames.add(propertyName);
}
src.append(SchemaHelper.extractProperties(schemaNode, propertyNames, validators, compoundIndexKeys, enums, viewProperties, propertyValidators, errorBuffer));
SchemaHelper.extractViews(schemaNode, viewProperties, relationshipPropertyNames, errorBuffer);
SchemaHelper.extractMethods(schemaNode, methods);
// output possible enum definitions
for (final String enumDefition : enums) {
src.append(enumDefition);
}
for (Entry<String, Set<String>> entry : viewProperties.entrySet()) {
final String viewName = entry.getKey();
final Set<String> view = entry.getValue();
if (!view.isEmpty()) {
schemaNode.addDynamicView(viewName);
SchemaHelper.formatView(src, _className, viewName, viewName, view);
}
}
if (schemaNode.getProperty(defaultSortKey) != null) {
String order = schemaNode.getProperty(defaultSortOrder);
if (order == null || "desc".equals(order)) {
order = "GraphObjectComparator.DESCENDING";
} else {
order = "GraphObjectComparator.ASCENDING";
}
src.append("\n\t@Override\n");
src.append("\tpublic PropertyKey getDefaultSortKey() {\n");
src.append("\t\treturn ").append(schemaNode.getProperty(defaultSortKey)).append("Property;\n");
src.append("\t}\n");
src.append("\n\t@Override\n");
src.append("\tpublic String getDefaultSortOrder() {\n");
src.append("\t\treturn ").append(order).append(";\n");
src.append("\t}\n");
}
SchemaHelper.formatValidators(src, validators, compoundIndexKeys, extendsAbstractNode, propertyValidators);
SchemaHelper.formatMethods(schemaNode, src, methods, implementedInterfaces);
// insert dynamic code here
src.append(mixinCodeBuffer);
// insert source code from module
for (final StructrModule module : modules) {
module.insertSourceCode(schemaNode, src);
}
src.append("}\n");
return src.toString();
}
use of org.structr.core.app.App in project structr by structr.
the class SchemaHelper method extractMethods.
public static void extractMethods(final AbstractSchemaNode entity, final Map<String, List<ActionEntry>> actions) throws FrameworkException {
final PropertyContainer propertyContainer = entity.getPropertyContainer();
for (final String rawActionName : getActions(propertyContainer)) {
if (propertyContainer.hasProperty(rawActionName)) {
final String value = propertyContainer.getProperty(rawActionName).toString();
if (entity instanceof AbstractSchemaNode) {
final AbstractSchemaNode schemaNode = (AbstractSchemaNode) entity;
final App app = StructrApp.getInstance();
final String methodName = rawActionName.substring(3);
if (app.nodeQuery(SchemaMethod.class).and(SchemaMethod.schemaNode, schemaNode).and(AbstractNode.name, methodName).getFirst() == null) {
app.create(SchemaMethod.class, new NodeAttribute<>(SchemaMethod.schemaNode, schemaNode), new NodeAttribute<>(SchemaMethod.name, methodName), new NodeAttribute<>(SchemaMethod.source, value));
schemaNode.removeProperty(new StringProperty(rawActionName));
}
}
}
}
final List<SchemaMethod> schemaMethods = entity.getSchemaMethods();
if (schemaMethods != null) {
for (final SchemaMethod schemaMethod : schemaMethods) {
final ActionEntry entry = schemaMethod.getActionEntry(entity);
final String name = entry.getName();
List<ActionEntry> actionList = actions.get(name);
if (actionList == null) {
actionList = new LinkedList<>();
actions.put(name, actionList);
}
actionList.add(entry);
Collections.sort(actionList);
}
}
}
use of org.structr.core.app.App in project structr by structr.
the class SchemaHelper method extractViews.
public static void extractViews(final Schema entity, final Map<String, Set<String>> views, final Set<String> relPropertyNames, final ErrorBuffer errorBuffer) throws FrameworkException {
final PropertyContainer propertyContainer = entity.getPropertyContainer();
final ConfigurationProvider config = StructrApp.getConfiguration();
Class superClass = config.getNodeEntityClass(entity.getSuperclassName());
if (superClass == null) {
superClass = config.getRelationshipEntityClass(entity.getSuperclassName());
}
if (superClass == null) {
superClass = AbstractNode.class;
}
for (final String rawViewName : getViews(propertyContainer)) {
if (!rawViewName.startsWith("___") && propertyContainer.hasProperty(rawViewName)) {
final String value = propertyContainer.getProperty(rawViewName).toString();
final String[] parts = value.split("[,\\s]+");
final String viewName = rawViewName.substring(2);
if (entity instanceof AbstractSchemaNode) {
final List<String> nonGraphProperties = new LinkedList<>();
final List<SchemaProperty> properties = new LinkedList<>();
final AbstractSchemaNode schemaNode = (AbstractSchemaNode) entity;
final App app = StructrApp.getInstance();
if (app.nodeQuery(SchemaView.class).and(SchemaView.schemaNode, schemaNode).and(AbstractNode.name, viewName).getFirst() == null) {
// add parts to view, overrides defaults (because of clear() above)
for (int i = 0; i < parts.length; i++) {
String propertyName = parts[i].trim();
while (propertyName.startsWith("_")) {
propertyName = propertyName.substring(1);
}
// append this as a workaround to include remote properties
if (propertyName.endsWith("Property")) {
propertyName = propertyName.substring(0, propertyName.length() - "Property".length());
}
final SchemaProperty propertyNode = app.nodeQuery(SchemaProperty.class).and(SchemaProperty.schemaNode, schemaNode).andName(propertyName).getFirst();
if (propertyNode != null) {
properties.add(propertyNode);
} else {
nonGraphProperties.add(propertyName);
}
}
app.create(SchemaView.class, new NodeAttribute<>(SchemaView.schemaNode, schemaNode), new NodeAttribute<>(SchemaView.schemaProperties, properties), new NodeAttribute<>(SchemaView.name, viewName), new NodeAttribute<>(SchemaView.nonGraphProperties, StringUtils.join(nonGraphProperties, ",")));
schemaNode.removeProperty(new StringProperty(rawViewName));
}
}
}
}
final List<SchemaView> schemaViews = entity.getSchemaViews();
if (schemaViews != null) {
for (final SchemaView schemaView : schemaViews) {
final String nonGraphProperties = schemaView.getProperty(SchemaView.nonGraphProperties);
final String viewName = schemaView.getName();
// clear view before filling it again
Set<String> view = views.get(viewName);
if (view == null) {
view = new LinkedHashSet<>();
views.put(viewName, view);
}
final List<SchemaProperty> schemaProperties = schemaView.getProperty(SchemaView.schemaProperties);
for (final SchemaProperty property : schemaProperties) {
if (property.getProperty(SchemaProperty.isBuiltinProperty) && !property.getProperty(SchemaProperty.isDynamic)) {
view.add(SchemaHelper.cleanPropertyName(property.getPropertyName()));
} else {
view.add(SchemaHelper.cleanPropertyName(property.getPropertyName() + "Property"));
}
}
// add properties that are not part of the graph
if (StringUtils.isNotBlank(nonGraphProperties)) {
for (final String propertyName : nonGraphProperties.split("[, ]+")) {
if (SchemaHelper.isDynamic(entity.getClassName(), propertyName)) {
view.add(SchemaHelper.cleanPropertyName(propertyName + "Property"));
} else if (relPropertyNames.contains(propertyName)) {
view.add(SchemaHelper.cleanPropertyName(propertyName) + "Property");
} else if (basePropertyNames.contains(propertyName)) {
view.add(SchemaHelper.cleanPropertyName(propertyName));
} else {
logger.warn("Unknown property {} in non-graph properties, ignoring.", propertyName);
SchemaHelper.isDynamic(entity.getClassName(), propertyName);
}
}
}
final String order = schemaView.getProperty(SchemaView.sortOrder);
if (order != null) {
applySortOrder(view, order);
}
}
}
}
use of org.structr.core.app.App in project structr by structr.
the class SchemaService method reloadSchema.
public static boolean reloadSchema(final ErrorBuffer errorBuffer, final String initiatedBySessionId) {
final ConfigurationProvider config = StructrApp.getConfiguration();
final App app = StructrApp.getInstance();
boolean success = true;
// compiling must only be done once
if (compiling.compareAndSet(false, true)) {
try {
final Map<String, Map<String, PropertyKey>> removedClasses = new HashMap<>(config.getTypeAndPropertyMapping());
final Map<String, GraphQLType> graphQLTypes = new LinkedHashMap<>();
final NodeExtender nodeExtender = new NodeExtender(initiatedBySessionId);
final Set<String> dynamicViews = new LinkedHashSet<>();
try (final Tx tx = app.tx()) {
// collect auto-generated schema nodes
SchemaService.ensureBuiltinTypesExist();
// add schema nodes from database
for (final SchemaNode schemaInfo : app.nodeQuery(SchemaNode.class).getAsList()) {
schemaInfo.handleMigration();
final String sourceCode = SchemaHelper.getSource(schemaInfo, errorBuffer);
if (sourceCode != null) {
final String className = schemaInfo.getClassName();
// only load dynamic node if there were no errors while generating
// the source code (missing modules etc.)
nodeExtender.addClass(className, sourceCode);
dynamicViews.addAll(schemaInfo.getDynamicViews());
// initialize GraphQL engine as well
schemaInfo.initializeGraphQL(graphQLTypes);
}
}
// collect relationship classes
for (final SchemaRelationshipNode schemaRelationship : app.nodeQuery(SchemaRelationshipNode.class).getAsList()) {
nodeExtender.addClass(schemaRelationship.getClassName(), schemaRelationship.getSource(errorBuffer));
dynamicViews.addAll(schemaRelationship.getDynamicViews());
// initialize GraphQL engine as well
schemaRelationship.initializeGraphQL(graphQLTypes);
}
// this is a very critical section :)
synchronized (SchemaService.class) {
// clear propagating relationship cache
SchemaRelationshipNode.clearPropagatingRelationshipTypes();
// compile all classes at once and register
final Map<String, Class> newTypes = nodeExtender.compile(errorBuffer);
for (final Class newType : newTypes.values()) {
// instantiate classes to execute static initializer of helpers
try {
// do full reload
config.registerEntityType(newType);
newType.newInstance();
} catch (Throwable ignore) {
}
}
// calculate difference between previous and new classes
removedClasses.keySet().removeAll(StructrApp.getConfiguration().getTypeAndPropertyMapping().keySet());
}
// create properties and views etc.
for (final SchemaNode schemaNode : app.nodeQuery(SchemaNode.class).getAsList()) {
schemaNode.createBuiltInSchemaEntities(errorBuffer);
}
success = !errorBuffer.hasError();
if (success) {
// prevent inheritance map from leaking
SearchCommand.clearInheritanceMap();
AccessPathCache.invalidate();
// clear relationship instance cache
AbstractNode.clearRelationshipTemplateInstanceCache();
// clear permission cache
AbstractNode.clearPermissionResolutionCache();
// inject views in configuration provider
config.registerDynamicViews(dynamicViews);
if (Services.calculateHierarchy() || !Services.isTesting()) {
calculateHierarchy();
}
if (Services.updateIndexConfiguration() || !Services.isTesting()) {
updateIndexConfiguration(removedClasses);
}
tx.success();
final GraphQLObjectType.Builder queryTypeBuilder = GraphQLObjectType.newObject();
// register types in "Query" type
for (final Entry<String, GraphQLType> entry : graphQLTypes.entrySet()) {
final String className = entry.getKey();
final GraphQLType type = entry.getValue();
// register type in query type
queryTypeBuilder.field(GraphQLFieldDefinition.newFieldDefinition().name(className).type(new GraphQLList(type)).argument(GraphQLArgument.newArgument().name("id").type(Scalars.GraphQLString).build()).argument(GraphQLArgument.newArgument().name("type").type(Scalars.GraphQLString).build()).argument(GraphQLArgument.newArgument().name("name").type(Scalars.GraphQLString).build()).argument(GraphQLArgument.newArgument().name("_page").type(Scalars.GraphQLInt).build()).argument(GraphQLArgument.newArgument().name("_pageSize").type(Scalars.GraphQLInt).build()).argument(GraphQLArgument.newArgument().name("_sort").type(Scalars.GraphQLString).build()).argument(GraphQLArgument.newArgument().name("_desc").type(Scalars.GraphQLBoolean).build()));
}
// exchange graphQL schema after successful build
synchronized (SchemaService.class) {
graphQLSchema = GraphQLSchema.newSchema().query(queryTypeBuilder.name("Query").build()).build(new LinkedHashSet<>(graphQLTypes.values()));
}
}
} catch (FrameworkException fex) {
logger.error("Unable to compile dynamic schema: {}", fex.getMessage());
success = false;
errorBuffer.getErrorTokens().addAll(fex.getErrorBuffer().getErrorTokens());
} catch (Throwable t) {
t.printStackTrace();
logger.error("Unable to compile dynamic schema: {}", t.getMessage());
success = false;
}
if (!success) {
if (Settings.SchemAutoMigration.getValue()) {
// handle migration in separate transaction
try (final Tx tx = app.tx()) {
// try to handle certain errors automatically
handleAutomaticMigration(errorBuffer);
tx.success();
} catch (FrameworkException fex) {
}
} else {
logger.error("Unable to compile dynamic schema, and automatic migration is not enabled. Please set application.schema.automigration = true in structr.conf to enable modification of existing schema classes.");
}
}
} finally {
// compiling done
compiling.set(false);
}
}
return success;
}
use of org.structr.core.app.App in project structr by structr.
the class ActionContext method getJavascriptLibraryCode.
public String getJavascriptLibraryCode(String fileName) {
synchronized (libraryCache) {
String cachedSource = libraryCache.get(fileName);
if (cachedSource == null) {
final StringBuilder buf = new StringBuilder();
final App app = StructrApp.getInstance();
try (final Tx tx = app.tx()) {
final List<JavaScriptSource> jsFiles = app.nodeQuery(JavaScriptSource.class).and(JavaScriptSource.name, fileName).and(StructrApp.key(JavaScriptSource.class, "useAsJavascriptLibrary"), true).getAsList();
if (jsFiles.isEmpty()) {
logger.warn("No JavaScript library file found with fileName: {}", fileName);
} else if (jsFiles.size() > 1) {
logger.warn("Multiple JavaScript library files found with fileName: {}. This may cause problems!", fileName);
}
for (final JavaScriptSource jsLibraryFile : jsFiles) {
final String contentType = jsLibraryFile.getContentType();
if (contentType != null) {
final String lowerCaseContentType = contentType.toLowerCase();
if ("text/javascript".equals(lowerCaseContentType) || "application/javascript".equals(lowerCaseContentType)) {
buf.append(jsLibraryFile.getJavascriptLibraryCode());
} else {
logger.info("Ignoring file {} for use as a Javascript library, content type {} not allowed. Use text/javascript or application/javascript.", new Object[] { jsLibraryFile.getName(), contentType });
}
} else {
logger.info("Ignoring file {} for use as a Javascript library, content type not set. Use text/javascript or application/javascript.", new Object[] { jsLibraryFile.getName(), contentType });
}
}
tx.success();
} catch (FrameworkException fex) {
logger.warn("", fex);
}
cachedSource = buf.toString();
libraryCache.put(fileName, cachedSource);
}
return cachedSource;
}
}
Aggregations