use of org.structr.core.property.PropertyKey in project structr by structr.
the class ValidationTest method testArrayPropertyNotNullValidation.
// ----- array property validation tests -----
@Test
public void testArrayPropertyNotNullValidation() {
final String keyName = "stringArray";
final Class testType = createTypeWithProperty("Test", keyName, "+String[]");
final PropertyKey key = StructrApp.key(testType, keyName);
if (key != null) {
try (final Tx tx = app.tx()) {
app.create(testType, new NodeAttribute<>(key, null));
tx.success();
fail("Array property validation failed!");
} catch (FrameworkException fex) {
final ErrorToken token = fex.getErrorBuffer().getErrorTokens().get(0);
assertEquals("Invalid uniqueness validation result", 422, fex.getStatus());
assertEquals("Invalid uniqueness validation result", keyName, token.getProperty());
assertEquals("Invalid uniqueness validation result", "Test", token.getType());
assertEquals("Invalid uniqueness validation result", "must_not_be_empty", token.getToken());
}
}
}
use of org.structr.core.property.PropertyKey in project structr by structr.
the class CsvServlet method doGet.
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws UnsupportedEncodingException {
Authenticator authenticator = null;
Result result = null;
Resource resource = null;
try {
// isolate request authentication in a transaction
try (final Tx tx = StructrApp.getInstance().tx()) {
authenticator = config.getAuthenticator();
securityContext = authenticator.initializeAndExamineRequest(request, response);
tx.success();
}
final App app = StructrApp.getInstance(securityContext);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/csv; charset=utf-8");
// set default value for property view
propertyView.set(securityContext, defaultPropertyView);
// evaluate constraints and measure query time
double queryTimeStart = System.nanoTime();
// isolate resource authentication
try (final Tx tx = app.tx()) {
resource = ResourceHelper.optimizeNestedResourceChain(securityContext, request, resourceMap, propertyView);
authenticator.checkResourceAccess(securityContext, request, resource.getResourceSignature(), propertyView.get(securityContext));
tx.success();
}
try (final Tx tx = app.tx()) {
String resourceSignature = resource.getResourceSignature();
// let authenticator examine request again
authenticator.checkResourceAccess(securityContext, request, resourceSignature, propertyView.get(securityContext));
// add sorting & paging
String pageSizeParameter = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_PAGE_SIZE);
String pageParameter = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_PAGE_NUMBER);
String sortOrder = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_SORT_ORDER);
String sortKeyName = request.getParameter(JsonRestServlet.REQUEST_PARAMETER_SORT_KEY);
boolean sortDescending = (sortOrder != null && "desc".equals(sortOrder.toLowerCase()));
int pageSize = Services.parseInt(pageSizeParameter, NodeFactory.DEFAULT_PAGE_SIZE);
int page = Services.parseInt(pageParameter, NodeFactory.DEFAULT_PAGE);
PropertyKey sortKey = null;
// set sort key
if (sortKeyName != null) {
Class<? extends GraphObject> type = resource.getEntityClass();
sortKey = StructrApp.getConfiguration().getPropertyKeyForDatabaseName(type, sortKeyName, false);
}
// Should line breaks be removed?
removeLineBreaks = StringUtils.equals(request.getParameter(REMOVE_LINE_BREAK_PARAM), "1");
// Should a leading BOM be written?
writeBom = StringUtils.equals(request.getParameter(WRITE_BOM), "1");
// do action
result = resource.doGet(sortKey, sortDescending, pageSize, page);
if (result != null) {
result.setIsCollection(resource.isCollectionResource());
result.setIsPrimitiveArray(resource.isPrimitiveArray());
PagingHelper.addPagingParameter(result, pageSize, page);
// timing..
final double queryTimeEnd = System.nanoTime();
// store property view that will be used to render the results
result.setPropertyView(propertyView.get(securityContext));
// allow resource to modify result set
resource.postProcessResultSet(result);
DecimalFormat decimalFormat = new DecimalFormat("0.000000000", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
result.setQueryTime(decimalFormat.format((queryTimeEnd - queryTimeStart) / 1000000000.0));
Writer writer = response.getWriter();
if (writeBom) {
writeUtf8Bom(writer);
}
// gson.toJson(result, writer);
writeCsv(result, writer, propertyView.get(securityContext));
response.setStatus(HttpServletResponse.SC_OK);
writer.flush();
writer.close();
} else {
logger.warn("Result was null!");
int code = HttpServletResponse.SC_NO_CONTENT;
response.setStatus(code);
Writer writer = response.getWriter();
writer.flush();
writer.close();
}
tx.success();
}
} catch (FrameworkException frameworkException) {
// set status
response.setStatus(frameworkException.getStatus());
} catch (JsonSyntaxException jsex) {
logger.warn("JsonSyntaxException in GET", jsex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
} catch (JsonParseException jpex) {
logger.warn("JsonParseException in GET", jpex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
} catch (Throwable t) {
logger.warn("Exception in GET", t);
int code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
response.setStatus(code);
}
}
use of org.structr.core.property.PropertyKey in project structr by structr.
the class CsvServlet method writeCsv.
/**
* Write list of objects to output
*
* @param result
* @param out
* @param propertyView
* @throws IOException
*/
public static void writeCsv(final Result result, final Writer out, final String propertyView) throws IOException {
final List<GraphObject> list = result.getResults();
final StringBuilder row = new StringBuilder();
boolean headerWritten = false;
for (final GraphObject obj : list) {
// Write column headers
if (!headerWritten) {
row.setLength(0);
for (PropertyKey key : obj.getPropertyKeys(propertyView)) {
row.append("\"").append(key.dbName()).append("\"").append(DEFAULT_FIELD_SEPARATOR);
}
// remove last ;
int pos = row.lastIndexOf("" + DEFAULT_FIELD_SEPARATOR);
if (pos >= 0) {
row.deleteCharAt(pos);
}
// append DOS-style line feed as defined in RFC 4180
out.append(row).append("\r\n");
// flush each line
out.flush();
headerWritten = true;
}
row.setLength(0);
for (PropertyKey key : obj.getPropertyKeys(propertyView)) {
Object value = obj.getProperty(key);
row.append("\"").append((value != null ? escapeForCsv(value) : "")).append("\"").append(DEFAULT_FIELD_SEPARATOR);
}
// remove last ;
row.deleteCharAt(row.lastIndexOf("" + DEFAULT_FIELD_SEPARATOR));
out.append(row).append("\r\n");
// flush each line
out.flush();
}
}
use of org.structr.core.property.PropertyKey in project structr by structr.
the class JsonRestServlet method doGetOrHead.
private void doGetOrHead(final HttpServletRequest request, final HttpServletResponse response, final boolean returnContent) throws ServletException, IOException {
SecurityContext securityContext = null;
Authenticator authenticator = null;
Result result = null;
Resource resource = null;
try {
// first thing to do!
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
// isolate request authentication in a transaction
try (final Tx tx = StructrApp.getInstance().tx()) {
authenticator = config.getAuthenticator();
securityContext = authenticator.initializeAndExamineRequest(request, response);
tx.success();
}
final App app = StructrApp.getInstance(securityContext);
// set default value for property view
propertyView.set(securityContext, config.getDefaultPropertyView());
// evaluate constraints and measure query time
double queryTimeStart = System.nanoTime();
// isolate resource authentication
try (final Tx tx = app.tx()) {
resource = ResourceHelper.applyViewTransformation(request, securityContext, ResourceHelper.optimizeNestedResourceChain(securityContext, request, resourceMap, propertyView), propertyView);
authenticator.checkResourceAccess(securityContext, request, resource.getResourceSignature(), propertyView.get(securityContext));
tx.success();
}
// add sorting & paging
String pageSizeParameter = request.getParameter(REQUEST_PARAMETER_PAGE_SIZE);
String pageParameter = request.getParameter(REQUEST_PARAMETER_PAGE_NUMBER);
String sortOrder = request.getParameter(REQUEST_PARAMETER_SORT_ORDER);
String sortKeyName = request.getParameter(REQUEST_PARAMETER_SORT_KEY);
String outputDepth = request.getParameter(REQUEST_PARAMTER_OUTPUT_DEPTH);
boolean sortDescending = (sortOrder != null && "desc".equals(sortOrder.toLowerCase()));
int pageSize = Services.parseInt(pageSizeParameter, NodeFactory.DEFAULT_PAGE_SIZE);
int page = Services.parseInt(pageParameter, NodeFactory.DEFAULT_PAGE);
int depth = Services.parseInt(outputDepth, config.getOutputNestingDepth());
String baseUrl = request.getRequestURI();
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);
}
// isolate doGet
boolean retry = true;
while (retry) {
try (final Tx tx = app.tx()) {
result = resource.doGet(sortKey, sortDescending, pageSize, page);
tx.success();
retry = false;
} catch (RetryException ddex) {
retry = true;
}
}
if (result == null) {
throw new FrameworkException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Unable to retrieve result, check database connection");
}
if (returnContent) {
if (!(resource instanceof StaticRelationshipResource) && !result.isPrimitiveArray() && !result.isEmpty()) {
result.setIsCollection(resource.isCollectionResource());
result.setIsPrimitiveArray(resource.isPrimitiveArray());
}
PagingHelper.addPagingParameter(result, pageSize, page);
// timing..
double queryTimeEnd = System.nanoTime();
// store property view that will be used to render the results
result.setPropertyView(propertyView.get(securityContext));
// allow resource to modify result set
resource.postProcessResultSet(result);
DecimalFormat decimalFormat = new DecimalFormat("0.000000000", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
result.setQueryTime(decimalFormat.format((queryTimeEnd - queryTimeStart) / 1000000000.0));
if (outputDepth != null) {
result.setOutputNestingDepth(depth);
}
String accept = request.getHeader("Accept");
if (accept != null && accept.contains("text/html")) {
final StreamingHtmlWriter htmlStreamer = new StreamingHtmlWriter(this.propertyView, indentJson, depth);
// isolate write output
try (final Tx tx = app.tx()) {
// no trailing semicolon so we dont trip MimeTypes.getContentTypeWithoutCharset
response.setContentType("text/html; charset=utf-8");
final Writer writer = response.getWriter();
htmlStreamer.stream(securityContext, writer, result, baseUrl);
// useful newline
writer.append("\n");
tx.success();
}
} else {
final StreamingJsonWriter jsonStreamer = new StreamingJsonWriter(this.propertyView, indentJson, depth);
// isolate write output
try (final Tx tx = app.tx()) {
// no trailing semicolon so we dont trip MimeTypes.getContentTypeWithoutCharset
response.setContentType("application/json; charset=utf-8");
final Writer writer = response.getWriter();
jsonStreamer.stream(securityContext, writer, result, baseUrl);
// useful newline
writer.append("\n");
tx.success();
}
}
}
response.setStatus(HttpServletResponse.SC_OK);
} catch (FrameworkException frameworkException) {
// set status & write JSON output
response.setStatus(frameworkException.getStatus());
gson.get().toJson(frameworkException, response.getWriter());
response.getWriter().println();
} catch (JsonSyntaxException jsex) {
logger.warn("JsonSyntaxException in GET", jsex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Json syntax exception in GET: " + jsex.getMessage()));
} catch (JsonParseException jpex) {
logger.warn("JsonParseException in GET", jpex);
int code = HttpServletResponse.SC_BAD_REQUEST;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Parser exception in GET: " + jpex.getMessage()));
} catch (Throwable t) {
logger.warn("Exception in GET (URI: {})", securityContext != null ? securityContext.getCompoundRequestURI() : "(null SecurityContext)");
logger.warn(" => Error thrown: ", t);
int code = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
response.setStatus(code);
response.getWriter().append(RestMethodResult.jsonError(code, "Exception in GET: " + t.getMessage()));
} finally {
try {
// response.getWriter().flush();
response.getWriter().close();
} catch (Throwable t) {
logger.warn("Unable to flush and close response: {}", t.getMessage());
}
}
}
use of org.structr.core.property.PropertyKey in project structr by structr.
the class StreamingWriter method stream.
public void stream(final SecurityContext securityContext, final Writer output, final Result result, final String baseUrl) throws IOException {
long t0 = System.nanoTime();
RestWriter writer = getRestWriter(securityContext, output);
if (indent) {
writer.setIndent(" ");
}
// result fields in alphabetical order
List<? extends GraphObject> results = result.getResults();
Integer outputNestingDepth = result.getOutputNestingDepth();
Integer page = result.getPage();
Integer pageCount = result.getPageCount();
Integer pageSize = result.getPageSize();
String queryTime = result.getQueryTime();
Integer resultCount = result.getRawResultCount();
String searchString = result.getSearchString();
String sortKey = result.getSortKey();
String sortOrder = result.getSortOrder();
GraphObject metaData = result.getMetaData();
writer.beginDocument(baseUrl, propertyView.get(securityContext));
// open result set
writer.beginObject();
if (outputNestingDepth != null) {
writer.name("output_nesting_depth").value(outputNestingDepth);
}
if (page != null) {
writer.name("page").value(page);
}
if (pageCount != null) {
writer.name("page_count").value(pageCount);
}
if (pageSize != null) {
writer.name("page_size").value(pageSize);
}
if (queryTime != null) {
writer.name("query_time").value(queryTime);
}
if (resultCount != null && renderResultCount) {
writer.name("result_count").value(resultCount);
}
if (results != null) {
if (results.isEmpty() && result.isPrimitiveArray()) {
writer.name(resultKeyName).nullValue();
} else if (results.isEmpty() && !result.isPrimitiveArray()) {
writer.name(resultKeyName).beginArray().endArray();
} else if (result.isPrimitiveArray()) {
writer.name(resultKeyName);
if (results.size() > 1) {
writer.beginArray();
}
for (final Object object : results) {
if (object != null) {
if (object instanceof GraphObject) {
// keep track of serialization time
final long startTime = System.currentTimeMillis();
final String localPropertyView = propertyView.get(null);
final GraphObject obj = (GraphObject) object;
final Iterator<PropertyKey> keyIt = obj.getPropertyKeys(localPropertyView).iterator();
while (keyIt.hasNext()) {
PropertyKey k = keyIt.next();
Object value = obj.getProperty(k);
root.serializeProperty(writer, k, value, localPropertyView, 0);
}
// check for timeout
if (System.currentTimeMillis() > startTime + MAX_SERIALIZATION_TIME) {
logger.error("JSON serialization of {} with {} results took more than {} ms, aborted. Please review output view size or adjust timeout.", new Object[] { securityContext.getCompoundRequestURI(), results.size(), MAX_SERIALIZATION_TIME });
// TODO: create some output indicating that streaming was interrupted
break;
}
} else {
writer.value(object.toString());
}
}
}
if (results.size() > 1) {
writer.endArray();
}
} else {
// result is an attribute called via REST API
if (results.size() > 1 && !result.isCollection()) {
throw new IllegalStateException(result.getClass().getSimpleName() + " is not a collection resource, but result set has size " + results.size());
}
// keep track of serialization time
long startTime = System.currentTimeMillis();
String localPropertyView = propertyView.get(null);
if (result.isCollection()) {
writer.name(resultKeyName).beginArray();
// serialize list of results
for (GraphObject graphObject : results) {
root.serialize(writer, graphObject, localPropertyView, 0);
// check for timeout
if (System.currentTimeMillis() > startTime + MAX_SERIALIZATION_TIME) {
logger.error("JSON serialization of {} with {} results took more than {} ms, aborted. Please review output view size or adjust timeout.", new Object[] { securityContext.getRequest().getRequestURI().concat((securityContext.getRequest().getQueryString() == null) ? "" : "?".concat(securityContext.getRequest().getQueryString())), results.size(), MAX_SERIALIZATION_TIME });
// TODO: create some output indicating that streaming was interrupted
break;
}
}
writer.endArray();
} else {
writer.name(resultKeyName);
root.serialize(writer, results.get(0), localPropertyView, 0);
}
}
}
if (searchString != null) {
writer.name("search_string").value(searchString);
}
if (sortKey != null) {
writer.name("sort_key").value(sortKey);
}
if (sortOrder != null) {
writer.name("sort_order").value(sortOrder);
}
if (metaData != null) {
String localPropertyView = propertyView.get(null);
writer.name("meta_data");
root.serialize(writer, metaData, localPropertyView, 0);
}
if (renderSerializationTime) {
writer.name("serialization_time").value(decimalFormat.format((System.nanoTime() - t0) / 1000000000.0));
}
// finished
writer.endObject();
writer.endDocument();
}
Aggregations