use of org.structr.module.StructrModule in project structr by structr.
the class DeployCommand method doImport.
// ----- private methods -----
private void doImport(final Map<String, Object> attributes) throws FrameworkException {
final long startTime = System.currentTimeMillis();
customHeaders.put("start", new Date(startTime).toString());
final String path = (String) attributes.get("source");
final SecurityContext ctx = SecurityContext.getSuperUserInstance();
final App app = StructrApp.getInstance(ctx);
ctx.setDoTransactionNotifications(false);
ctx.disableEnsureCardinality();
ctx.disableModificationOfAccessTime();
final Map<String, Object> componentsConf = new HashMap<>();
final Map<String, Object> templatesConf = new HashMap<>();
final Map<String, Object> pagesConf = new HashMap<>();
final Map<String, Object> filesConf = new HashMap<>();
if (StringUtils.isBlank(path)) {
throw new FrameworkException(422, "Please provide 'source' attribute for deployment source directory path.");
}
final Path source = Paths.get(path);
if (!Files.exists(source)) {
throw new FrameworkException(422, "Source path " + path + " does not exist.");
}
if (!Files.isDirectory(source)) {
throw new FrameworkException(422, "Source path " + path + " is not a directory.");
}
final Map<String, Object> broadcastData = new HashMap();
broadcastData.put("type", DEPLOYMENT_IMPORT_STATUS);
broadcastData.put("subtype", DEPLOYMENT_STATUS_BEGIN);
broadcastData.put("start", startTime);
broadcastData.put("source", source);
TransactionCommand.simpleBroadcastGenericMessage(broadcastData);
// apply configuration
final Path preDeployConf = source.resolve("pre-deploy.conf");
if (Files.exists(preDeployConf)) {
try (final Tx tx = app.tx()) {
final String confSource = new String(Files.readAllBytes(preDeployConf), Charset.forName("utf-8")).trim();
if (confSource.length() > 0) {
info("Applying pre-deployment configuration from {}", preDeployConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Applying pre-deployment configuration");
Scripting.evaluate(new ActionContext(ctx), null, confSource, "pre-deploy.conf");
} else {
info("Ignoring empty pre-deployment configuration {}", preDeployConf);
}
tx.success();
} catch (Throwable t) {
logger.warn("", t);
publishDeploymentWarningMessage("Exception caught while importing pre-deploy.conf", t.toString());
}
}
// backup previous value of change log setting
// temporary disable creation of change log
final boolean changeLogEnabled = Settings.ChangelogEnabled.getValue();
Settings.ChangelogEnabled.setValue(false);
// read grants.json
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing resource access grants");
final Path grantsConf = source.resolve("security/grants.json");
if (Files.exists(grantsConf)) {
info("Reading {}", grantsConf);
importListData(ResourceAccess.class, readConfigList(grantsConf));
}
// read schema-methods.json
final Path schemaMethodsConf = source.resolve("schema-methods.json");
if (Files.exists(schemaMethodsConf)) {
info("Reading {}", schemaMethodsConf);
final String title = "Deprecation warning";
final String text = "Found file 'schema-methods.json'. Newer versions store global schema methods in the schema snapshot file. Recreate the export with the current version to avoid compatibility issues. Support for importing this file will be dropped in future versions.";
info(title + ": " + text);
publishDeploymentWarningMessage(title, text);
importListData(SchemaMethod.class, readConfigList(schemaMethodsConf));
}
// read mail-templates.json
final Path mailTemplatesConf = source.resolve("mail-templates.json");
if (Files.exists(mailTemplatesConf)) {
info("Reading {}", mailTemplatesConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing mail templates");
importListData(MailTemplate.class, readConfigList(mailTemplatesConf));
}
// read widgets.json
final Path widgetsConf = source.resolve("widgets.json");
if (Files.exists(widgetsConf)) {
info("Reading {}", widgetsConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing widgets");
importListData(Widget.class, readConfigList(widgetsConf));
}
// read localizations.json
final Path localizationsConf = source.resolve("localizations.json");
if (Files.exists(localizationsConf)) {
final PropertyMap additionalData = new PropertyMap();
// Question: shouldn't this be true? No, 'imported' is a flag for legacy-localization which
// have been imported from a legacy-system which was replaced by structr.
// it is a way to differentiate between new and old localization strings
additionalData.put(StructrApp.key(Localization.class, "imported"), false);
info("Reading {}", localizationsConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing localizations");
importListData(Localization.class, readConfigList(localizationsConf), additionalData);
}
// read files.conf
final Path filesConfFile = source.resolve("files.json");
if (Files.exists(filesConfFile)) {
info("Reading {}", filesConfFile);
filesConf.putAll(readConfigMap(filesConfFile));
}
// read pages.conf
final Path pagesConfFile = source.resolve("pages.json");
if (Files.exists(pagesConfFile)) {
info("Reading {}", pagesConfFile);
pagesConf.putAll(readConfigMap(pagesConfFile));
}
// read components.conf
final Path componentsConfFile = source.resolve("components.json");
if (Files.exists(componentsConfFile)) {
info("Reading {}", componentsConfFile);
componentsConf.putAll(readConfigMap(componentsConfFile));
}
// read templates.conf
final Path templatesConfFile = source.resolve("templates.json");
if (Files.exists(templatesConfFile)) {
info("Reading {}", templatesConfFile);
templatesConf.putAll(readConfigMap(templatesConfFile));
}
// import schema
final Path schema = source.resolve("schema");
if (Files.exists(schema)) {
try {
info("Importing data from schema/ directory");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing schema");
Files.walkFileTree(schema, new SchemaImportVisitor(schema));
} catch (IOException ioex) {
logger.warn("Exception while importing schema", ioex);
}
}
// import files
final Path files = source.resolve("files");
if (Files.exists(files)) {
try {
info("Importing files (unchanged files will be skipped)");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing files");
FileImportVisitor fiv = new FileImportVisitor(files, filesConf);
Files.walkFileTree(files, fiv);
fiv.handleDeferredFiles();
} catch (IOException ioex) {
logger.warn("Exception while importing files", ioex);
}
}
for (StructrModule module : StructrApp.getConfiguration().getModules().values()) {
if (module.hasDeploymentData()) {
info("Importing deployment data for module {}", module.getName());
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing deployment data for module " + module.getName());
final Path moduleFolder = source.resolve("modules/" + module.getName() + "/");
module.importDeploymentData(moduleFolder, getGson());
}
}
// construct paths
final Path templates = source.resolve("templates");
final Path components = source.resolve("components");
final Path pages = source.resolve("pages");
// an empty directory was specified accidentially).
if (Files.exists(templates) && Files.exists(components) && Files.exists(pages)) {
try (final Tx tx = app.tx()) {
final String tenantIdentifier = app.getDatabaseService().getTenantIdentifier();
info("Removing pages, templates and components");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Removing pages, templates and components");
if (tenantIdentifier != null) {
app.cypher("MATCH (n:" + tenantIdentifier + ":DOMNode) DETACH DELETE n", null);
} else {
app.cypher("MATCH (n:DOMNode) DETACH DELETE n", null);
}
FlushCachesCommand.flushAll();
tx.success();
}
} else {
logger.info("Import directory does not seem to contain pages, templates or components, NOT removing any data.");
}
// import templates, must be done before pages so the templates exist
if (Files.exists(templates)) {
try {
info("Importing templates");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing templates");
Files.walkFileTree(templates, new TemplateImportVisitor(templatesConf));
} catch (IOException ioex) {
logger.warn("Exception while importing templates", ioex);
}
}
// import components, must be done before pages so the shared components exist
if (Files.exists(components)) {
try {
info("Importing shared components");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing shared components");
Files.walkFileTree(components, new ComponentImportVisitor(componentsConf));
} catch (IOException ioex) {
logger.warn("Exception while importing shared components", ioex);
}
}
// import pages
if (Files.exists(pages)) {
try {
info("Importing pages");
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Importing pages");
Files.walkFileTree(pages, new PageImportVisitor(pages, pagesConf));
} catch (IOException ioex) {
logger.warn("Exception while importing pages", ioex);
}
}
try (final Tx tx = app.tx()) {
deferredPageLinks.forEach((String linkableUUID, String pagePath) -> {
try {
final DOMNode page = StructrApp.getInstance().get(DOMNode.class, linkableUUID);
final Linkable linkedPage = StructrApp.getInstance().nodeQuery(Linkable.class).and(StructrApp.key(Page.class, "path"), pagePath).or(Page.name, pagePath).getFirst();
((LinkSource) page).setLinkable(linkedPage);
} catch (FrameworkException ex) {
}
});
deferredPageLinks.clear();
tx.success();
}
// apply configuration
final Path postDeployConf = source.resolve("post-deploy.conf");
if (Files.exists(postDeployConf)) {
try (final Tx tx = app.tx()) {
final String confSource = new String(Files.readAllBytes(postDeployConf), Charset.forName("utf-8")).trim();
if (confSource.length() > 0) {
info("Applying post-deployment configuration from {}", postDeployConf);
publishDeploymentProgressMessage(DEPLOYMENT_IMPORT_STATUS, "Applying post-deployment configuration");
Scripting.evaluate(new ActionContext(ctx), null, confSource, "post-deploy.conf");
} else {
info("Ignoring empty post-deployment configuration {}", postDeployConf);
}
tx.success();
} catch (Throwable t) {
logger.warn("", t);
publishDeploymentWarningMessage("Exception caught while importing post-deploy.conf", t.toString());
}
}
// restore saved value
Settings.ChangelogEnabled.setValue(changeLogEnabled);
final long endTime = System.currentTimeMillis();
DecimalFormat decimalFormat = new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
final String duration = decimalFormat.format(((endTime - startTime) / 1000.0)) + "s";
customHeaders.put("end", new Date(endTime).toString());
customHeaders.put("duration", duration);
info("Import from {} done. (Took {})", source.toString(), duration);
broadcastData.put("subtype", DEPLOYMENT_STATUS_END);
broadcastData.put("end", endTime);
broadcastData.put("duration", duration);
TransactionCommand.simpleBroadcastGenericMessage(broadcastData);
}
use of org.structr.module.StructrModule in project structr by structr.
the class CSVFileImportJob method runInitialChecks.
@Override
public boolean runInitialChecks() throws FrameworkException {
final String targetType = getOrDefault(configuration.get("targetType"), null);
final String delimiter = getOrDefault(configuration.get("delimiter"), ";");
final String quoteChar = getOrDefault(configuration.get("quoteChar"), "\"");
if (targetType == null || delimiter == null || quoteChar == null) {
throw new FrameworkException(400, "Cannot import CSV, please specify target type, delimiter and quote character.");
} else {
final StructrModule module = StructrApp.getConfiguration().getModules().get("api-builder");
if (module == null || !(module instanceof APIBuilder)) {
throw new FrameworkException(400, "Cannot import CSV, API builder module is not available.");
}
}
return true;
}
use of org.structr.module.StructrModule 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.module.StructrModule in project structr by structr.
the class VersionHelper method updateModuleList.
public static void updateModuleList() {
modules.clear();
// collect StructrModules
for (final StructrModule module : StructrApp.getConfiguration().getModules().values()) {
final Map<String, Object> map = new LinkedHashMap<>();
map.put("source", module.getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if (module.getDependencies() != null) {
map.put("dependencies", module.getDependencies());
}
if (module.getFeatures() != null) {
map.put("features", module.getFeatures());
}
modules.put(module.getName(), map);
}
}
use of org.structr.module.StructrModule in project structr by structr.
the class StructrApp method getFulltextIndexer.
@Override
public FulltextIndexer getFulltextIndexer(final Object... params) {
final Map<String, StructrModule> modules = StructrApp.getConfiguration().getModules();
final StructrModule module = modules.get("text-search");
if (module != null && module instanceof FulltextIndexer) {
return (FulltextIndexer) module;
}
return new DummyFulltextIndexer();
}
Aggregations