public void test04SearchByLocation() { try { final PropertyMap props = new PropertyMap(); final PropertyKey lat = TestSeven.latitude; final PropertyKey lon = TestSeven.longitude; final String type = TestSeven.class.getSimpleName(); props.put(lat, 50.12284d); props.put(lon, 8.73923d); props.put(AbstractNode.name, "TestSeven-0"); AbstractNode node = createTestNode(type, props); boolean includeDeletedAndHidden = true; boolean publicOnly = false; List<SearchAttribute> searchAttributes = new LinkedList<SearchAttribute>(); searchAttributes.add(new TextualSearchAttribute(AbstractNode.type, type, SearchOperator.AND)); searchAttributes.add( new DistanceSearchAttribute( "Hanauer Landstr. 200, 60314 Frankfurt, Germany", 10.0, SearchOperator.AND)); Result result = searchNodeCommand.execute(includeDeletedAndHidden, publicOnly, searchAttributes); assertEquals(1, result.size()); assertTrue(result.get(0).equals(node)); } catch (FrameworkException ex) { logger.log(Level.SEVERE, ex.toString()); fail("Unexpected exception"); } }
@Override public void deleteData(final int offset, final int count) throws DOMException { checkWriteAccess(); // finally, set content to concatenated left and right parts try { Services.command(securityContext, TransactionCommand.class) .execute( new StructrTransaction() { @Override public Object execute() throws FrameworkException { String text = getProperty(content); String leftPart = text.substring(0, offset); String rightPart = text.substring(offset + count); setProperty(content, leftPart.concat(rightPart)); return null; } }); } catch (FrameworkException fex) { throw new DOMException(DOMException.INVALID_STATE_ERR, fex.toString()); } }
@Override public void appendData(final String data) throws DOMException { checkWriteAccess(); // set content to concatenated text and data try { Services.command(securityContext, TransactionCommand.class) .execute( new StructrTransaction() { @Override public Object execute() throws FrameworkException { String text = getProperty(content); setProperty(content, text.concat(data)); return null; } }); } catch (FrameworkException fex) { throw new DOMException(DOMException.INVALID_STATE_ERR, fex.toString()); } }
@Override public void processMessage(final WebSocketMessage webSocketData) { final GraphObject obj = getGraphObject(webSocketData.getId()); String key = (String) webSocketData.getNodeData().get("key"); if (obj != null) { PropertyKey propertyKey = StructrApp.getConfiguration().getPropertyKeyForJSONName(obj.getClass(), key); PropertyConverter converter = propertyKey.inputConverter(getWebSocket().getSecurityContext()); Object value = obj.getProperty(propertyKey); if (converter != null) { try { value = converter.revert(value); } catch (FrameworkException ex) { getWebSocket() .send(MessageBuilder.status().code(400).message(ex.getMessage()).build(), true); } } webSocketData.setNodeData(key, value); // send only over local connection (no broadcast) getWebSocket().send(webSocketData, true); } else { getWebSocket().send(MessageBuilder.status().code(404).build(), true); } }
public void test02SearchSingleNodeByDate() { try { PropertyMap props = new PropertyMap(); PropertyKey key = TestOne.aDate; Date date = new Date(); String type = TestOne.class.getSimpleName(); props.put(key, date); AbstractNode node = createTestNode(type, props); boolean includeDeletedAndHidden = true; boolean publicOnly = false; List<SearchAttribute> searchAttributes = new LinkedList<SearchAttribute>(); searchAttributes.add(new TextualSearchAttribute(AbstractNode.type, type, SearchOperator.AND)); searchAttributes.add(new FilterSearchAttribute(key, date, SearchOperator.AND)); Result result = searchNodeCommand.execute(includeDeletedAndHidden, publicOnly, searchAttributes); assertEquals(1, result.size()); assertTrue(result.get(0).equals(node)); } catch (FrameworkException ex) { logger.log(Level.SEVERE, ex.toString()); fail("Unexpected exception"); } }
@Override public void processMessage(final WebSocketMessage webSocketData) { final SecurityContext securityContext = getWebSocket().getSecurityContext(); final int pageSize = webSocketData.getPageSize(); final int page = webSocketData.getPage(); final App app = StructrApp.getInstance(securityContext); try (final Tx tx = app.tx()) { // do search List<AbstractNode> filteredResults = getUnattachedNodes(app, securityContext, webSocketData); // save raw result count int resultCountBeforePaging = filteredResults.size(); // set full result list webSocketData.setResult(PagingHelper.subList(filteredResults, pageSize, page, null)); webSocketData.setRawResultCount(resultCountBeforePaging); // send only over local connection getWebSocket().send(webSocketData, true); tx.success(); } catch (FrameworkException fex) { logger.warn("Exception occured", fex); getWebSocket() .send( MessageBuilder.status().code(fex.getStatus()).message(fex.getMessage()).build(), true); } }
@Override public <T> Comparable getComparableProperty(final PropertyKey<T> key) { if (key != null) { final T propertyValue = getProperty(key, false, null); // get "raw" property without converter // check property converter PropertyConverter converter = key.databaseConverter(securityContext, this); if (converter != null) { try { return converter.convertForSorting(propertyValue); } catch (FrameworkException fex) { logger.log( Level.WARNING, "Unable to convert property {0} of type {1}: {2}", new Object[] {key.dbName(), getClass().getSimpleName(), fex.getMessage()}); } } // conversion failed, may the property value itself is comparable if (propertyValue instanceof Comparable) { return (Comparable) propertyValue; } // last try: convertFromInput to String to make comparable if (propertyValue != null) { return propertyValue.toString(); } } return null; }
@Override public void cancelCheckout(final Payment payment) throws FrameworkException { // this is a no-op in the PayPal API, we only have to set the payment state try { payment.setToken(null); payment.setPaymentState(PaymentState.cancelled); } catch (FrameworkException fex) { fex.printStackTrace(); } }
@Override public void processMessage(WebSocketMessage webSocketData) { final SecurityContext securityContext = getWebSocket().getSecurityContext(); final App app = StructrApp.getInstance(securityContext); final String id = webSocketData.getId(); try (final Tx tx = app.tx()) { final Page page = app.get(Page.class, id); final List<GraphObject> result = new LinkedList<>(); if (page != null) { collectActiveElements(result, page, Collections.EMPTY_SET, null, 0); // set full result list webSocketData.setResult(result); webSocketData.setRawResultCount(result.size()); // send only over local connection getWebSocket().send(webSocketData, true); } else { getWebSocket() .send( MessageBuilder.status() .code(404) .message("Page with ID " + id + " not found.") .build(), true); } } catch (FrameworkException fex) { logger.log(Level.WARNING, "Exception occured", fex); getWebSocket() .send( MessageBuilder.status().code(fex.getStatus()).message(fex.getMessage()).build(), true); } }
public void test01SearchSingleNodeByName() { try { PropertyMap props = new PropertyMap(); PropertyKey key = AbstractNode.name; String name = "89w3hklsdfghsdkljth"; props.put(key, name); AbstractNode node = createTestNode(TestOne.class.getSimpleName(), props); boolean includeDeletedAndHidden = true; boolean publicOnly = false; List<SearchAttribute> searchAttributes = new LinkedList<SearchAttribute>(); searchAttributes.add(new TextualSearchAttribute(key, name, SearchOperator.AND)); Result result = searchNodeCommand.execute(includeDeletedAndHidden, publicOnly, searchAttributes); assertTrue(result.size() == 1); assertTrue(result.get(0).equals(node)); // Change name attribute and search again name = "klppptzoehigösoiutzüw0e9hg"; node.setProperty(key, name); searchAttributes.clear(); searchAttributes.add(new TextualSearchAttribute(key, name, SearchOperator.AND)); result = searchNodeCommand.execute(includeDeletedAndHidden, publicOnly, searchAttributes); assertTrue(result.size() == 1); assertTrue(result.get(0).equals(node)); } catch (FrameworkException ex) { logger.log(Level.SEVERE, ex.toString()); fail("Unexpected exception"); } }
public void test03SearchRelationship() { try { AbstractRelationship rel = ((List<AbstractRelationship>) createTestRelationships(RelType.UNDEFINED, 1)).get(0); PropertyKey key1 = new StringProperty("jghsdkhgshdhgsdjkfgh"); String val1 = "54354354546806849870"; rel.setProperty(key1, val1); assertTrue(rel.getProperty(key1).equals(val1)); List<SearchAttribute> searchAttributes = new LinkedList<SearchAttribute>(); searchAttributes.add(Search.andExactProperty(key1, val1)); List<AbstractRelationship> result = (List<AbstractRelationship>) searchRelationshipCommand.execute(searchAttributes); assertTrue(result.size() == 1); assertTrue(result.get(0).equals(rel)); searchAttributes.clear(); val1 = "ölllldjöoa8w4rasf"; rel.setProperty(key1, val1); searchAttributes.add(Search.andExactProperty(key1, val1)); assertTrue(result.size() == 1); assertTrue(result.get(0).equals(rel)); } catch (FrameworkException ex) { logger.log(Level.SEVERE, ex.toString()); fail("Unexpected exception"); } }
@Override public void insertData(final int offset, final String data) throws DOMException { checkWriteAccess(); try { Services.command(securityContext, TransactionCommand.class) .execute( new StructrTransaction() { @Override public Object execute() throws FrameworkException { String text = getProperty(content); String leftPart = text.substring(0, offset); String rightPart = text.substring(offset); StringBuilder buf = new StringBuilder(text.length() + data.length() + 1); buf.append(leftPart); buf.append(data); buf.append(rightPart); // finally, set content to concatenated left, data and right parts setProperty(content, buf.toString()); return null; } }); } catch (FrameworkException fex) { throw new DOMException(DOMException.INVALID_STATE_ERR, fex.toString()); } }
public void test06DistanceSearchOnEmptyDB() { try { boolean includeDeletedAndHidden = true; boolean publicOnly = false; List<SearchAttribute> searchAttributes = new LinkedList<SearchAttribute>(); searchAttributes.add( new DistanceSearchAttribute( "Hanauer Landstr. 200, 60314 Frankfurt, Germany", 10.0, SearchOperator.AND)); Result result = searchNodeCommand.execute(includeDeletedAndHidden, publicOnly, searchAttributes); assertEquals(0, result.size()); } catch (FrameworkException ex) { logger.log(Level.SEVERE, ex.toString()); System.out.println(ex.toString()); fail("Unexpected exception"); } }
@Override public Text splitText(int offset) throws DOMException { checkWriteAccess(); String text = getProperty(content); if (text != null) { int len = text.length(); if (offset < 0 || offset > len) { throw new DOMException(DOMException.INDEX_SIZE_ERR, INDEX_SIZE_ERR_MESSAGE); } else { final String firstPart = text.substring(0, offset); final String secondPart = text.substring(offset); final Document document = getOwnerDocument(); final Node parent = getParentNode(); if (document != null && parent != null) { try { return Services.command(securityContext, TransactionCommand.class) .execute( new StructrTransaction<Text>() { @Override public Text execute() throws FrameworkException { // first part goes into existing text element setProperty(content, firstPart); // second part goes into new text element Text newNode = document.createTextNode(secondPart); // make new node a child of old parent parent.appendChild(newNode); return newNode; } }); } catch (FrameworkException fex) { throw new DOMException(DOMException.INVALID_STATE_ERR, fex.toString()); } } else { throw new DOMException(DOMException.INVALID_STATE_ERR, CANNOT_SPLIT_TEXT_WITHOUT_PARENT); } } } throw new DOMException(DOMException.INDEX_SIZE_ERR, INDEX_SIZE_ERR_MESSAGE); }
@Override public void render(SecurityContext securityContext, RenderContext renderContext, int depth) throws FrameworkException { if (isDeleted() || isHidden() || !displayForLocale(renderContext) || !displayForConditions(securityContext, renderContext)) { return; } String id = getUuid(); EditMode edit = renderContext.getEditMode(securityContext.getUser(false)); boolean inBody = renderContext.inBody(); StringBuilder buffer = renderContext.getBuffer(); String _contentType = getProperty(contentType); // fetch content with variable replacement String _content = getPropertyWithVariableReplacement(securityContext, renderContext, Content.content); if (!(EditMode.RAW.equals(edit)) && (_contentType == null || ("text/plain".equals(_contentType)))) { _content = escapeForHtml(_content); } if (EditMode.CONTENT.equals(edit) && inBody && securityContext.isAllowed(this, Permission.write)) { if ("text/javascript".equals(_contentType)) { // Javascript will only be given some local vars // TODO: Is this neccessary? buffer .append("// data-structr-type='") .append(getType()) .append("'\n// data-structr-id='") .append(id) .append("'\n"); } else if ("text/css".equals(_contentType)) { // CSS will only be given some local vars // TODO: Is this neccessary? buffer .append("/* data-structr-type='") .append(getType()) .append("'*/\n/* data-structr-id='") .append(id) .append("'*/\n"); } else { // // In edit mode, add an artificial 'span' tag around content nodes within body to make // them editable // buffer.append("<span data-structr-raw-value=\"").append(getProperty(Content.content)) // //.append("\" // data-structr-content-type=\"").append(StringUtils.defaultString(getProperty(Content.contentType), "")) // .append("\" data-structr-type=\"").append(getType()) // .append("\" data-structr-id=\"").append(id).append("\">"); // int l = buffer.length(); // buffer.replace(l-1, l, " data-structr-raw-value=\"" // .concat(getProperty(Content.content)) // .concat("\" data-structr-type=\"").concat(getType()) // .concat("\" data-structr-id=\"").concat(id).concat("\">")); buffer.append( "<!--data-structr-id=\"" .concat(id) .concat("\" data-structr-raw-value=\"") .concat(getProperty(Content.content).replaceAll("\n", "\\\\n")) .concat("\"-->")); // .concat("\" // data-structr-raw-value=\"").concat(getProperty(Content.content)).concat("\"-->")); } } // No contentType-specific rendering in DATA edit mode // if (!edit.equals(EditMode.DATA)) { // examine content type and apply converter if (_contentType != null) { Adapter<String, String> converter = contentConverters.get(_contentType); if (converter != null) { try { // apply adapter _content = converter.adapt(_content); } catch (FrameworkException fex) { logger.log(Level.WARNING, "Unable to convert content: {0}", fex.getMessage()); } } } // replace newlines with <br /> for rendering if (((_contentType == null) || _contentType.equals("text/plain")) && (_content != null) && !_content.isEmpty()) { _content = _content.replaceAll("[\\n]{1}", "<br>"); } // } if (_content != null) { // buffer.append(indent(depth, true)).append(_content); // insert whitespace to make element clickable if (EditMode.CONTENT.equals(edit) && _content.length() == 0) { _content = "--- empty ---"; } buffer.append(_content); } if (EditMode.CONTENT.equals(edit) && inBody && !("text/javascript".equals(getProperty(contentType))) && !("text/css".equals(getProperty(contentType)))) { // buffer.append("</span>"); buffer.append("<!---->"); } }
@Override public void onWebSocketText(final String data) { if (data == null) { logger.log(Level.WARNING, "Empty text message received."); return; } logger.log( Level.FINE, "############################################################ RECEIVED \n{0}", data.substring(0, Math.min(data.length(), 1000))); // parse web socket data from JSON final WebSocketMessage webSocketData = gson.fromJson(data, WebSocketMessage.class); final App app = StructrApp.getInstance(securityContext); try (final Tx tx = app.tx()) { this.callback = webSocketData.getCallback(); final String command = webSocketData.getCommand(); final Class type = commandSet.get(command); final String sessionIdFromMessage = webSocketData.getSessionId(); if (type != null) { if (sessionIdFromMessage != null) { // try to authenticated this connection by sessionId authenticate(sessionIdFromMessage); } // we only permit LOGIN commands if authentication based on sessionId was not successful if (!isAuthenticated() && !type.equals(LoginCommand.class)) { // send 401 Authentication Required send(MessageBuilder.status().code(401).message("").build(), true); return; } AbstractCommand abstractCommand = (AbstractCommand) type.newInstance(); abstractCommand.setWebSocket(this); abstractCommand.setSession(session); abstractCommand.setIdProperty(idProperty); // store authenticated-Flag in webSocketData // so the command can access it webSocketData.setSessionValid(isAuthenticated()); // process message try { abstractCommand.processMessage(webSocketData); // commit transaction tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(System.out); // send 400 Bad Request send(MessageBuilder.status().code(400).message(fex.toString()).build(), true); } } else { logger.log(Level.WARNING, "Unknow command {0}", command); // send 400 Bad Request send(MessageBuilder.status().code(400).message("Unknown command").build(), true); } } catch (FrameworkException | IllegalAccessException | InstantiationException t) { logger.log(Level.WARNING, "Unable to parse message.", t); } }
@Override protected void doGet(final HttpServletRequest request, final HttpServletResponse response) { final Authenticator auth = config.getAuthenticator(); final SecurityContext securityContext; final App app; try { String path = request.getPathInfo(); // check for registration (has its own tx because of write access if (checkRegistration(auth, request, response, path)) { return; } // isolate request authentication in a transaction try (final Tx tx = StructrApp.getInstance().tx()) { securityContext = auth.initializeAndExamineRequest(request, response); tx.success(); } app = StructrApp.getInstance(securityContext); try (final Tx tx = app.tx()) { // Ensure access mode is frontend securityContext.setAccessMode(AccessMode.Frontend); request.setCharacterEncoding("UTF-8"); // Important: Set character encoding before calling response.getWriter() !!, see Servlet // Spec 5.4 response.setCharacterEncoding("UTF-8"); boolean dontCache = false; logger.log(Level.FINE, "Path info {0}", path); // don't continue on redirects if (response.getStatus() == 302) { return; } Principal user = securityContext.getUser(false); if (user != null) { // Don't cache if a user is logged in dontCache = true; } final RenderContext renderContext = RenderContext.getInstance(request, response, getEffectiveLocale(request)); renderContext.setResourceProvider(config.getResourceProvider()); EditMode edit = renderContext.getEditMode(user); DOMNode rootElement = null; AbstractNode dataNode = null; String[] uriParts = PathHelper.getParts(path); if ((uriParts == null) || (uriParts.length == 0)) { // find a visible page rootElement = findIndexPage(securityContext); logger.log(Level.FINE, "No path supplied, trying to find index page"); } else { if (rootElement == null) { rootElement = findPage(securityContext, request, path); } else { dontCache = true; } } if (rootElement == null) { // No page found // Look for a file File file = findFile(securityContext, request, path); if (file != null) { streamFile(securityContext, file, request, response, edit); return; } // store remaining path parts in request Matcher matcher = threadLocalUUIDMatcher.get(); boolean requestUriContainsUuids = false; for (int i = 0; i < uriParts.length; i++) { request.setAttribute(uriParts[i], i); matcher.reset(uriParts[i]); // set to "true" if part matches UUID pattern requestUriContainsUuids |= matcher.matches(); } if (!requestUriContainsUuids) { // Try to find a data node by name dataNode = findFirstNodeByName(securityContext, request, path); } else { dataNode = findNodeByUuid(securityContext, PathHelper.getName(path)); } if (dataNode != null) { // Last path part matches a data node // Remove last path part and try again searching for a page // clear possible entry points request.removeAttribute(POSSIBLE_ENTRY_POINTS); rootElement = findPage( securityContext, request, StringUtils.substringBeforeLast(path, PathHelper.PATH_SEP)); renderContext.setDetailsDataObject(dataNode); // Start rendering on data node if (rootElement == null && dataNode instanceof DOMNode) { rootElement = ((DOMNode) dataNode); } } } // Still nothing found, do error handling if (rootElement == null) { // Check if security context has set an 401 status if (response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) { try { UiAuthenticator.writeUnauthorized(response); } catch (IllegalStateException ise) { } } else { rootElement = notFound(response, securityContext); } } if (rootElement == null) { return; } if (EditMode.WIDGET.equals(edit) || dontCache) { setNoCacheHeaders(response); } if (!securityContext.isVisible(rootElement)) { rootElement = notFound(response, securityContext); if (rootElement == null) { return; } } if (securityContext.isVisible(rootElement)) { if (!EditMode.WIDGET.equals(edit) && !dontCache && notModifiedSince(request, response, rootElement, dontCache)) { ServletOutputStream out = response.getOutputStream(); out.flush(); // response.flushBuffer(); out.close(); } else { // prepare response response.setCharacterEncoding("UTF-8"); String contentType = rootElement.getProperty(Page.contentType); if (contentType != null && contentType.equals("text/html")) { contentType = contentType.concat(";charset=UTF-8"); response.setContentType(contentType); } else { // Default response.setContentType("text/html;charset=UTF-8"); } response.setHeader("Strict-Transport-Security", "max-age=60"); response.setHeader("X-Content-Type-Options", "nosniff"); response.setHeader("X-Frame-Options", "SAMEORIGIN"); response.setHeader("X-XSS-Protection", "1; mode=block"); // async or not? boolean isAsync = HttpService.parseBoolean( Services.getBaseConfiguration().getProperty(HttpService.ASYNC), true); if (isAsync) { final AsyncContext async = request.startAsync(); final ServletOutputStream out = async.getResponse().getOutputStream(); final AtomicBoolean finished = new AtomicBoolean(false); final DOMNode rootNode = rootElement; threadPool.submit( new Runnable() { @Override public void run() { try (final Tx tx = app.tx()) { // final long start = System.currentTimeMillis(); // render rootNode.render(securityContext, renderContext, 0); finished.set(true); // final long end = System.currentTimeMillis(); // System.out.println("Done in " + (end-start) + " ms"); tx.success(); } catch (Throwable t) { t.printStackTrace(); final String errorMsg = t.getMessage(); try { // response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorMsg); finished.set(true); } catch (IOException ex) { ex.printStackTrace(); } } } }); // start output write listener out.setWriteListener( new WriteListener() { @Override public void onWritePossible() throws IOException { try { final Queue<String> queue = renderContext.getBuffer().getQueue(); while (out.isReady()) { String buffer = null; synchronized (queue) { buffer = queue.poll(); } if (buffer != null) { out.print(buffer); } else { if (finished.get()) { async.complete(); response.setStatus(HttpServletResponse.SC_OK); // prevent this block from being called again break; } Thread.sleep(1); } } } catch (Throwable t) { t.printStackTrace(); } } @Override public void onError(Throwable t) { t.printStackTrace(); } }); } else { final StringRenderBuffer buffer = new StringRenderBuffer(); renderContext.setBuffer(buffer); // render rootElement.render(securityContext, renderContext, 0); response.getOutputStream().write(buffer.getBuffer().toString().getBytes("utf-8")); response.getOutputStream().flush(); response.getOutputStream().close(); } } } else { notFound(response, securityContext); } tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); logger.log(Level.SEVERE, "Exception while processing request", fex); } } catch (IOException | FrameworkException t) { t.printStackTrace(); logger.log(Level.SEVERE, "Exception while processing request", t); UiAuthenticator.writeInternalServerError(response); } }
public static void analyzeSchema() { final App app = StructrApp.getInstance(); final FileBasedHashLongMap<NodeInfo> nodeIdMap = new FileBasedHashLongMap<>(userHome + File.separator + ".structrSchemaAnalyzer"); final GraphDatabaseService graphDb = app.command(GraphDatabaseCommand.class).execute(); final ConfigurationProvider configuration = Services.getInstance().getConfigurationProvider(); final Set<NodeInfo> nodeTypes = new LinkedHashSet<>(); final Set<RelationshipInfo> relationships = new LinkedHashSet<>(); final Map<String, SchemaNode> schemaNodes = new LinkedHashMap<>(); final Map<String, List<TypeInfo>> typeInfoTypeMap = new LinkedHashMap<>(); final List<TypeInfo> reducedTypeInfos = new LinkedList<>(); final List<TypeInfo> typeInfos = new LinkedList<>(); Iterator<Relationship> relIterator = null; Iterator<Node> nodeIterator = null; logger.log(Level.INFO, "Fetching all nodes iterator.."); try (final Tx tx = app.tx()) { nodeIterator = Iterables.filter( new StructrAndSpatialPredicate(false, false, true), GlobalGraphOperations.at(graphDb).getAllNodes()) .iterator(); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } logger.log(Level.INFO, "Starting to analyze nodes.."); NodeServiceCommand.bulkGraphOperation( SecurityContext.getSuperUserInstance(), nodeIterator, 100000, "Analyzing nodes", new BulkGraphOperation<Node>() { @Override public void handleGraphObject(final SecurityContext securityContext, final Node node) throws FrameworkException { final NodeInfo nodeInfo = new NodeInfo(node); // hashcode of nodeInfo is derived from its property and type signature! nodeTypes.add(nodeInfo); // add node ID to our new test datastructure nodeIdMap.add(nodeInfo, node.getId()); } }); logger.log(Level.INFO, "Identifying common base classes.."); try (final Tx tx = app.tx(true, false, false)) { // nodeTypes now contains all existing node types and their property sets identifyCommonBaseClasses(app, nodeTypes, nodeIdMap, typeInfos); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } logger.log(Level.INFO, "Collecting type information.."); try (final Tx tx = app.tx(true, false, false)) { // group type infos by type collectTypeInfos(typeInfos, typeInfoTypeMap); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } logger.log(Level.INFO, "Aggregating type information.."); try (final Tx tx = app.tx(true, false, false)) { // reduce type infos with more than one type reduceTypeInfos(typeInfoTypeMap, reducedTypeInfos); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } logger.log(Level.INFO, "Identifying property sets.."); try (final Tx tx = app.tx(true, false, false)) { // intersect property sets of type infos intersectPropertySets(reducedTypeInfos); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } logger.log(Level.INFO, "Sorting result.."); try (final Tx tx = app.tx(false, false, false)) { // sort type infos Collections.sort(reducedTypeInfos, new HierarchyComparator(false)); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } final Map<String, TypeInfo> reducedTypeInfoMap = new LinkedHashMap<>(); for (final TypeInfo info : reducedTypeInfos) { final String type = info.getPrimaryType(); // map TypeInfo to type for later use reducedTypeInfoMap.put(type, info); logger.log(Level.INFO, "Starting with setting of type and ID for type {0}", type); NodeServiceCommand.bulkGraphOperation( SecurityContext.getSuperUserInstance(), info.getNodeIds().iterator(), 10000, "Setting type and ID", new BulkGraphOperation<Long>() { @Override public void handleGraphObject(SecurityContext securityContext, Long nodeId) throws FrameworkException { final Node node = graphDb.getNodeById(nodeId); node.setProperty(GraphObject.id.dbName(), NodeServiceCommand.getNextUuid()); node.setProperty(GraphObject.type.dbName(), type); } }); } logger.log(Level.INFO, "Fetching all relationships iterator.."); try (final Tx tx = app.tx(false, false, false)) { relIterator = Iterables.filter( new StructrAndSpatialPredicate(false, false, true), GlobalGraphOperations.at(graphDb).getAllRelationships()) .iterator(); tx.success(); } catch (FrameworkException fex) { fex.printStackTrace(); } logger.log(Level.INFO, "Starting with analyzing relationships.."); NodeServiceCommand.bulkGraphOperation( SecurityContext.getSuperUserInstance(), relIterator, 10000, "Analyzing relationships", new BulkGraphOperation<Relationship>() { @Override public void handleGraphObject(SecurityContext securityContext, Relationship rel) throws FrameworkException { final Node startNode = rel.getStartNode(); final Node endNode = rel.getEndNode(); // make sure node has been successfully identified above if (startNode.hasProperty("type") && endNode.hasProperty("type")) { final String relationshipType = rel.getType().name(); final String startNodeType = (String) startNode.getProperty("type"); final String endNodeType = (String) endNode.getProperty("type"); relationships.add(new RelationshipInfo(startNodeType, endNodeType, relationshipType)); // create combined type on imported relationship if (startNodeType != null && endNodeType != null) { final String combinedType = getCombinedType(startNodeType, relationshipType, endNodeType); logger.log( Level.FINE, "Combined relationship type {0} found for rel type {1}, start node type {2}, end node type {3}", new Object[] {combinedType, relationshipType, startNodeType, endNodeType}); rel.setProperty(GraphObject.type.dbName(), combinedType); } // create ID on imported relationship rel.setProperty(GraphObject.id.dbName(), NodeServiceCommand.getNextUuid()); } } }); logger.log(Level.INFO, "Grouping relationships.."); // group relationships by type final Map<String, List<RelationshipInfo>> relTypeInfoMap = new LinkedHashMap<>(); for (final RelationshipInfo relInfo : relationships) { // final String relType = relInfo.getRelType(); final String combinedType = getCombinedType( relInfo.getStartNodeType(), relInfo.getRelType(), relInfo.getEndNodeType()); List<RelationshipInfo> infos = relTypeInfoMap.get(combinedType); if (infos == null) { infos = new LinkedList<>(); relTypeInfoMap.put(combinedType, infos); } infos.add(relInfo); } logger.log(Level.INFO, "Aggregating relationship information.."); final List<RelationshipInfo> reducedRelationshipInfos = new ArrayList<>(); if ("true" .equals( Services.getInstance() .getConfigurationValue("importer.inheritancedetection", "true"))) { // reduce relationship infos into one for (final List<RelationshipInfo> infos : relTypeInfoMap.values()) { reducedRelationshipInfos.addAll(reduceNodeTypes(infos, reducedTypeInfoMap)); } } else { reducedRelationshipInfos.addAll(relationships); } logger.log(Level.INFO, "Starting with schema node creation.."); NodeServiceCommand.bulkGraphOperation( SecurityContext.getSuperUserInstance(), reducedTypeInfos.iterator(), 100000, "Creating schema nodes", new BulkGraphOperation<TypeInfo>() { @Override public void handleGraphObject(SecurityContext securityContext, TypeInfo typeInfo) throws FrameworkException { final String type = typeInfo.getPrimaryType(); if (!"ReferenceNode".equals(type)) { final Map<String, Class> props = typeInfo.getPropertySet(); final PropertyMap propertyMap = new PropertyMap(); // add properties for (final Map.Entry<String, Class> propertyEntry : props.entrySet()) { final String propertyName = propertyEntry.getKey(); final Class propertyType = propertyEntry.getValue(); // handle array types differently String propertyTypeName = propertyType.getSimpleName(); if (propertyType.isArray()) { // remove "[]" from the end and append "Array" to match the appropriate parser propertyTypeName = propertyTypeName.substring(0, propertyTypeName.length() - 2).concat("Array"); } propertyMap.put(new StringProperty("_".concat(propertyName)), propertyTypeName); } // set node type which is in "name" property propertyMap.put(AbstractNode.name, type); // check if there is an existing Structr entity with the same type // and make the dynamic class extend the existing class if yes. final Class existingType = configuration.getNodeEntityClass(type); if (existingType != null) { propertyMap.put(SchemaNode.extendsClass, existingType.getName()); } else if (!typeInfo.getOtherTypes().isEmpty()) { // only the first supertype is supported propertyMap.put( SchemaNode.extendsClass, typeInfo.getSuperclass(reducedTypeInfoMap)); } final SchemaNode existingNode = app.nodeQuery(SchemaNode.class).andName(type).getFirst(); if (existingNode != null) { for (final Entry<PropertyKey, Object> entry : propertyMap.entrySet()) { existingNode.setProperty(entry.getKey(), entry.getValue()); } schemaNodes.put(type, existingNode); } else { // create schema node schemaNodes.put(type, app.create(SchemaNode.class, propertyMap)); } } } }); logger.log(Level.INFO, "Starting with schema relationship creation.."); NodeServiceCommand.bulkGraphOperation( SecurityContext.getSuperUserInstance(), reducedRelationshipInfos.iterator(), 100000, "Creating schema relationships", new BulkGraphOperation<RelationshipInfo>() { @Override public void handleGraphObject(SecurityContext securityContext, RelationshipInfo template) throws FrameworkException { final SchemaNode startNode = schemaNodes.get(template.getStartNodeType()); final SchemaNode endNode = schemaNodes.get(template.getEndNodeType()); final String relationshipType = template.getRelType(); final PropertyMap propertyMap = new PropertyMap(); propertyMap.put(SchemaRelationshipNode.sourceId, startNode.getUuid()); propertyMap.put(SchemaRelationshipNode.targetId, endNode.getUuid()); propertyMap.put(SchemaRelationshipNode.relationshipType, relationshipType); app.create(SchemaRelationshipNode.class, propertyMap); } }); logger.log(Level.INFO, "Starting with index rebuild.."); // rebuild index app.command(BulkRebuildIndexCommand.class).execute(Collections.EMPTY_MAP); }
@Override public void processMessage(WebSocketMessage webSocketData) { final Map<String, Object> nodeData = webSocketData.getNodeData(); final String parentId = (String) nodeData.get("parentId"); final String childContent = (String) nodeData.get("childContent"); final String pageId = webSocketData.getPageId(); nodeData.remove("parentId"); if (pageId != null) { // check for parent ID before creating any nodes if (parentId == null) { getWebSocket() .send( MessageBuilder.status() .code(422) .message("Cannot add node without parentId") .build(), true); return; } // check if parent node with given ID exists final DOMNode parentNode = getDOMNode(parentId); if (parentNode == null) { getWebSocket() .send(MessageBuilder.status().code(404).message("Parent node not found").build(), true); return; } final Document document = getPage(pageId); if (document != null) { final String tagName = (String) nodeData.get("tagName"); final App app = StructrApp.getInstance(); nodeData.remove("tagName"); try { app.beginTx(); DOMNode newNode; if (tagName != null && !tagName.isEmpty()) { newNode = (DOMNode) document.createElement(tagName); } else { newNode = (DOMNode) document.createTextNode("#text"); } // append new node to parent if (newNode != null) { parentNode.appendChild(newNode); for (Entry entry : nodeData.entrySet()) { String key = (String) entry.getKey(); Object val = entry.getValue(); PropertyKey propertyKey = StructrApp.getConfiguration() .getPropertyKeyForDatabaseName(newNode.getClass(), key); if (propertyKey != null) { try { Object convertedValue = val; PropertyConverter inputConverter = propertyKey.inputConverter(SecurityContext.getSuperUserInstance()); if (inputConverter != null) { convertedValue = inputConverter.convert(val); } // newNode.unlockReadOnlyPropertiesOnce(); newNode.setProperty(propertyKey, convertedValue); } catch (FrameworkException fex) { logger.log( Level.WARNING, "Unable to set node property {0} of node {1} to {2}: {3}", new Object[] {propertyKey, newNode.getUuid(), val, fex.getMessage()}); } } } // create a child text node if content is given if (StringUtils.isNotBlank(childContent)) { DOMNode childNode = (DOMNode) document.createTextNode(childContent); if (newNode != null) { newNode.appendChild(childNode); } } } app.commitTx(); } catch (DOMException dex) { // send DOM exception getWebSocket() .send(MessageBuilder.status().code(422).message(dex.getMessage()).build(), true); } catch (FrameworkException ex) { Logger.getLogger(CreateAndAppendDOMNodeCommand.class.getName()) .log(Level.SEVERE, null, ex); } finally { app.finishTx(); } } else { getWebSocket() .send(MessageBuilder.status().code(404).message("Page not found").build(), true); } } else { getWebSocket() .send( MessageBuilder.status() .code(422) .message("Cannot create node without pageId") .build(), true); } }
@Override public Object setProperty( final SecurityContext securityContext, final GraphObject obj, final T value) throws FrameworkException { final PropertyConverter converter = databaseConverter(securityContext, obj); final Object convertedValue; if (converter != null) { convertedValue = converter.convert(value); } else { convertedValue = value; } final PropertyContainer propertyContainer = obj.getPropertyContainer(); if (propertyContainer != null) { if (!TransactionCommand.inTransaction()) { throw new NotInTransactionException("setProperty outside of transaction"); } boolean internalSystemPropertiesUnlocked = (obj instanceof CreationContainer); // notify only non-system properties // collect modified properties if (obj instanceof AbstractNode) { if (!unvalidated) { TransactionCommand.nodeModified( securityContext.getCachedUser(), (AbstractNode) obj, AbstractPrimitiveProperty.this, propertyContainer.hasProperty(dbName()) ? propertyContainer.getProperty(dbName()) : null, value); } internalSystemPropertiesUnlocked = ((AbstractNode) obj).internalSystemPropertiesUnlocked; } else if (obj instanceof AbstractRelationship) { if (!unvalidated) { TransactionCommand.relationshipModified( securityContext.getCachedUser(), (AbstractRelationship) obj, AbstractPrimitiveProperty.this, propertyContainer.hasProperty(dbName()) ? propertyContainer.getProperty(dbName()) : null, value); } internalSystemPropertiesUnlocked = ((AbstractRelationship) obj).internalSystemPropertiesUnlocked; } // catch all sorts of errors and wrap them in a FrameworkException try { // save space if (convertedValue == null) { propertyContainer.removeProperty(dbName()); } else { if (!isSystemInternal() || internalSystemPropertiesUnlocked) { propertyContainer.setProperty(dbName(), convertedValue); } else { logger.warn( "Tried to set internal system property {} to {}. Action was denied.", new Object[] {dbName(), convertedValue}); } } updateAccessInformation(securityContext, propertyContainer); } catch (Throwable t) { // throw FrameworkException with the given cause final FrameworkException fex = new FrameworkException( 500, "Unable to set property " + jsonName() + " on entity with ID " + obj.getUuid() + ": " + t.toString()); fex.initCause(t); throw fex; } if (isIndexed()) { // do indexing, needs to be done after // setProperty to make spatial index // work if (!isPassivelyIndexed()) { index(obj, convertedValue); } } } return null; }