stringList = new ArrayList<>(this.values.size());
+ for (Object value : this.values) {
+ stringList.add(value.toString());
+ }
+ return Collections.unmodifiableList(stringList);
+ }
+
+ @Nullable
+ Object getValue() {
+ return (!this.values.isEmpty() ? this.values.get(0) : null);
+ }
+
+ @Nullable
+ String getStringValue() {
+ return (!this.values.isEmpty() ? String.valueOf(this.values.get(0)) : null);
+ }
+
+ @Override
+ public String toString() {
+ return this.values.toString();
+ }
+
+}
diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java
new file mode 100644
index 00000000..b9190a86
--- /dev/null
+++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateCookie.java
@@ -0,0 +1,150 @@
+package eu.xenit.apix.rest.v1.bulk.response;
+
+import org.springframework.core.style.ToStringCreator;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.Cookie;
+import java.time.DateTimeException;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+
+public class IntermediateCookie extends Cookie {
+
+ private static final long serialVersionUID = 4312531139502726325L;
+
+
+ @Nullable
+ private ZonedDateTime expires;
+
+ @Nullable
+ private String sameSite;
+
+
+ /**
+ * Construct a new {@link IntermediateCookie} with the supplied name and value.
+ *
+ * @param name the name
+ * @param value the value
+ * @see Cookie#Cookie(String, String)
+ */
+ public IntermediateCookie(String name, String value) {
+ super(name, value);
+ }
+
+ /**
+ * Set the "Expires" attribute for this cookie.
+ *
+ * @since 5.1.11
+ */
+ public void setExpires(@Nullable ZonedDateTime expires) {
+ this.expires = expires;
+ }
+
+ /**
+ * Get the "Expires" attribute for this cookie.
+ *
+ * @return the "Expires" attribute for this cookie, or {@code null} if not set
+ * @since 5.1.11
+ */
+ @Nullable
+ public ZonedDateTime getExpires() {
+ return this.expires;
+ }
+
+ /**
+ * Set the "SameSite" attribute for this cookie.
+ * This limits the scope of the cookie such that it will only be attached
+ * to same-site requests if the supplied value is {@code "Strict"} or cross-site
+ * requests if the supplied value is {@code "Lax"}.
+ *
+ * @see RFC6265 bis
+ */
+ public void setSameSite(@Nullable String sameSite) {
+ this.sameSite = sameSite;
+ }
+
+ /**
+ * Get the "SameSite" attribute for this cookie.
+ *
+ * @return the "SameSite" attribute for this cookie, or {@code null} if not set
+ */
+ @Nullable
+ public String getSameSite() {
+ return this.sameSite;
+ }
+
+
+ /**
+ * Factory method that parses the value of the supplied "Set-Cookie" header.
+ *
+ * @param setCookieHeader the "Set-Cookie" value; never {@code null} or empty
+ * @return the created cookie
+ */
+ public static IntermediateCookie parse(String setCookieHeader) {
+ Assert.notNull(setCookieHeader, "Set-Cookie header must not be null");
+ String[] cookieParts = setCookieHeader.split("\\s*=\\s*", 2);
+ Assert.isTrue(cookieParts.length == 2, () -> "Invalid Set-Cookie header '" + setCookieHeader + "'");
+
+ String name = cookieParts[0];
+ String[] valueAndAttributes = cookieParts[1].split("\\s*;\\s*", 2);
+ String value = valueAndAttributes[0];
+ String[] attributes =
+ (valueAndAttributes.length > 1 ? valueAndAttributes[1].split("\\s*;\\s*") : new String[0]);
+
+ IntermediateCookie cookie = new IntermediateCookie(name, value);
+ for (String attribute : attributes) {
+ if (StringUtils.startsWithIgnoreCase(attribute, "Domain")) {
+ cookie.setDomain(extractAttributeValue(attribute, setCookieHeader));
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
+ cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
+ try {
+ cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
+ DateTimeFormatter.RFC_1123_DATE_TIME));
+ } catch (DateTimeException ex) {
+ // ignore invalid date formats
+ }
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
+ cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "Secure")) {
+ cookie.setSecure(true);
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "HttpOnly")) {
+ cookie.setHttpOnly(true);
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "SameSite")) {
+ cookie.setSameSite(extractAttributeValue(attribute, setCookieHeader));
+ } else if (StringUtils.startsWithIgnoreCase(attribute, "Comment")) {
+ cookie.setComment(extractAttributeValue(attribute, setCookieHeader));
+ }
+ }
+ return cookie;
+ }
+
+ private static String extractAttributeValue(String attribute, String header) {
+ String[] nameAndValue = attribute.split("=");
+ Assert.isTrue(nameAndValue.length == 2,
+ () -> "No value in attribute '" + nameAndValue[0] + "' for Set-Cookie header '" + header + "'");
+ return nameAndValue[1];
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringCreator(this)
+ .append("name", getName())
+ .append("value", getValue())
+ .append("Path", getPath())
+ .append("Domain", getDomain())
+ .append("Version", getVersion())
+ .append("Comment", getComment())
+ .append("Secure", getSecure())
+ .append("HttpOnly", isHttpOnly())
+ .append("SameSite", this.sameSite)
+ .append("Max-Age", getMaxAge())
+ .append("Expires", (this.expires != null ?
+ DateTimeFormatter.RFC_1123_DATE_TIME.format(this.expires) : null))
+ .toString();
+ }
+
+}
\ No newline at end of file
diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java
new file mode 100644
index 00000000..a240c31f
--- /dev/null
+++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/bulk/response/IntermediateResponse.java
@@ -0,0 +1,634 @@
+package eu.xenit.apix.rest.v1.bulk.response;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.LinkedCaseInsensitiveMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.util.WebUtils;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+
+public class IntermediateResponse implements HttpServletResponse {
+
+ private static final String CHARSET_PREFIX = "charset=";
+
+ private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+ private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+
+ //---------------------------------------------------------------------
+ // ServletResponse properties
+ //---------------------------------------------------------------------
+
+
+ private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
+
+ /**
+ * {@code true} if the character encoding has been explicitly set through
+ * {@link HttpServletResponse} methods or through a {@code charset} parameter
+ * on the {@code Content-Type}.
+ */
+ private boolean characterEncodingSet = false;
+
+ private final ByteArrayOutputStream content = new ByteArrayOutputStream(1024);
+
+ private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content);
+
+ @Nullable
+ private PrintWriter writer;
+
+
+ @Nullable
+ private String contentType;
+
+ private int bufferSize = 4096;
+
+ private boolean committed;
+
+ private Locale locale = Locale.getDefault();
+
+
+ //---------------------------------------------------------------------
+ // HttpServletResponse properties
+ //---------------------------------------------------------------------
+
+
+ private final Map headers = new LinkedCaseInsensitiveMap<>();
+
+ private int status = HttpServletResponse.SC_OK;
+
+
+ //---------------------------------------------------------------------
+ // ServletResponse interface
+ //---------------------------------------------------------------------
+
+
+ @Override
+ public void setCharacterEncoding(String characterEncoding) {
+ setExplicitCharacterEncoding(characterEncoding);
+ updateContentTypePropertyAndHeader();
+ }
+
+ private void setExplicitCharacterEncoding(String characterEncoding) {
+ Assert.notNull(characterEncoding, "'characterEncoding' must not be null");
+ this.characterEncoding = characterEncoding;
+ this.characterEncodingSet = true;
+ }
+
+ private void updateContentTypePropertyAndHeader() {
+ if (this.contentType != null) {
+ String value = this.contentType;
+ if (this.characterEncodingSet && !value.toLowerCase().contains(CHARSET_PREFIX)) {
+ value += ';' + CHARSET_PREFIX + getCharacterEncoding();
+ this.contentType = value;
+ }
+ doAddHeaderValue(HttpHeaders.CONTENT_TYPE, value, true);
+ }
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return this.characterEncoding;
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() {
+ boolean outputStreamAccessAllowed = true;
+ Assert.state(outputStreamAccessAllowed, "OutputStream access not allowed");
+ return this.outputStream;
+ }
+
+ @Override
+ public PrintWriter getWriter() throws UnsupportedEncodingException {
+ boolean writerAccessAllowed = true;
+ Assert.state(writerAccessAllowed, "Writer access not allowed");
+ if (this.writer == null) {
+ Writer targetWriter = new OutputStreamWriter(this.content, getCharacterEncoding());
+ this.writer = new ResponsePrintWriter(targetWriter);
+ }
+ return this.writer;
+ }
+
+
+ /**
+ * Get the content of the response body as a {@code String}, using the charset
+ * specified for the response by the application, either through
+ * {@link HttpServletResponse} methods or through a charset parameter on the
+ * {@code Content-Type}. If no charset has been explicitly defined, they
+ * will be used.
+ *
+ * @return the content as a {@code String}
+ * @throws UnsupportedEncodingException if the character encoding is not supported
+ * @see #setCharacterEncoding(String)
+ * @see #setContentType(String)
+ */
+ public String getContentAsString() throws UnsupportedEncodingException {
+ return this.content.toString(getCharacterEncoding());
+ }
+
+
+ @Override
+ public void setContentLength(int contentLength) {
+ doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true);
+ }
+
+
+ @Override
+ public void setContentLengthLong(long contentLength) {
+ doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true);
+ }
+
+
+ @Override
+ public void setContentType(@Nullable String contentType) {
+ this.contentType = contentType;
+ if (contentType != null) {
+ try {
+ MediaType mediaType = MediaType.parseMediaType(contentType);
+ if (mediaType.getCharset() != null) {
+ setExplicitCharacterEncoding(mediaType.getCharset().name());
+ }
+ } catch (Exception ex) {
+ // Try to get charset value anyway
+ int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
+ if (charsetIndex != -1) {
+ setExplicitCharacterEncoding(contentType.substring(charsetIndex + CHARSET_PREFIX.length()));
+ }
+ }
+ updateContentTypePropertyAndHeader();
+ }
+ }
+
+ @Override
+ @Nullable
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ @Override
+ public void setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ @Override
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ @Override
+ public void flushBuffer() {
+ setCommitted(true);
+ }
+
+ @Override
+ public void resetBuffer() {
+ Assert.state(!isCommitted(), "Cannot reset buffer - response is already committed");
+ this.content.reset();
+ }
+
+ private void setCommittedIfBufferSizeExceeded() {
+ int bufSize = getBufferSize();
+ if (bufSize > 0 && this.content.size() > bufSize) {
+ setCommitted(true);
+ }
+ }
+
+ public void setCommitted(boolean committed) {
+ this.committed = committed;
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return this.committed;
+ }
+
+ @Override
+ public void reset() {
+ resetBuffer();
+ this.characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
+ this.characterEncodingSet = false;
+ this.contentType = null;
+ this.locale = Locale.getDefault();
+ this.headers.clear();
+ this.status = HttpServletResponse.SC_OK;
+ }
+
+ @Override
+ public void setLocale(@Nullable Locale locale) {
+ // Although the Javadoc for javax.servlet.ServletResponse.setLocale(Locale) does not
+ // state how a null value for the supplied Locale should be handled, both Tomcat and
+ // Jetty simply ignore a null value. So we do the same here.
+ if (locale == null) {
+ return;
+ }
+ this.locale = locale;
+ doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, locale.toLanguageTag(), true);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+
+ //---------------------------------------------------------------------
+ // HttpServletResponse interface
+ //---------------------------------------------------------------------
+
+ @Override
+ public void addCookie(Cookie cookie) {
+ Assert.notNull(cookie, "Cookie must not be null");
+ doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), false);
+ }
+
+ private String getCookieHeader(Cookie cookie) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(cookie.getName()).append('=').append(cookie.getValue() == null ? "" : cookie.getValue());
+ if (StringUtils.hasText(cookie.getPath())) {
+ buf.append("; Path=").append(cookie.getPath());
+ }
+ if (StringUtils.hasText(cookie.getDomain())) {
+ buf.append("; Domain=").append(cookie.getDomain());
+ }
+ int maxAge = cookie.getMaxAge();
+ ZonedDateTime expires = (cookie instanceof IntermediateCookie ? ((IntermediateCookie) cookie).getExpires() : null);
+ if (maxAge >= 0) {
+ buf.append("; Max-Age=").append(maxAge);
+ buf.append("; Expires=");
+ if (expires != null) {
+ buf.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
+ } else {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
+ buf.append(headers.getFirst(HttpHeaders.EXPIRES));
+ }
+ } else if (expires != null) {
+ buf.append("; Expires=");
+ buf.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
+ }
+
+ if (cookie.getSecure()) {
+ buf.append("; Secure");
+ }
+ if (cookie.isHttpOnly()) {
+ buf.append("; HttpOnly");
+ }
+ if (cookie instanceof IntermediateCookie) {
+ IntermediateCookie intermediateCookie = (IntermediateCookie) cookie;
+ if (StringUtils.hasText(intermediateCookie.getSameSite())) {
+ buf.append("; SameSite=").append(intermediateCookie.getSameSite());
+ }
+ }
+ if (StringUtils.hasText(cookie.getComment())) {
+ buf.append("; Comment=").append(cookie.getComment());
+ }
+ return buf.toString();
+ }
+
+
+ @Override
+ public boolean containsHeader(String name) {
+ return this.headers.containsKey(name);
+ }
+
+ /**
+ * Return the names of all specified headers as a Set of Strings.
+ * As of Servlet 3.0, this method is also defined in {@link HttpServletResponse}.
+ *
+ * @return the {@code Set} of header name {@code Strings}, or an empty {@code Set} if none
+ */
+ @Override
+ public Collection getHeaderNames() {
+ return this.headers.keySet();
+ }
+
+ /**
+ * Return the primary value for the given header as a String, if any.
+ * Will return the first value in case of multiple values.
+ * As of Servlet 3.0, this method is also defined in {@link HttpServletResponse}.
+ * As of Spring 3.1, it returns a stringified value for Servlet 3.0 compatibility.
+ *
+ * @param name the name of the header
+ * @return the associated header value, or {@code null} if none
+ */
+ @Override
+ @Nullable
+ public String getHeader(String name) {
+ HeaderValueHolder header = this.headers.get(name);
+ return (header != null ? header.getStringValue() : null);
+ }
+
+ /**
+ * Return all values for the given header as a List of Strings.
+ *
As of Servlet 3.0, this method is also defined in {@link HttpServletResponse}.
+ * As of Spring 3.1, it returns a List of stringified values for Servlet 3.0 compatibility.
+ *
+ * @param name the name of the header
+ * @return the associated header values, or an empty List if none
+ */
+ @Override
+ public List getHeaders(String name) {
+ HeaderValueHolder header = this.headers.get(name);
+ if (header != null) {
+ return header.getStringValues();
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * The default implementation returns the given URL String as-is.
+ * Can be overridden in subclasses, appending a session id or the like.
+ */
+ @Override
+ public String encodeURL(String url) {
+ return url;
+ }
+
+ /**
+ * The default implementation delegates to {@link #encodeURL},
+ * returning the given URL String as-is.
+ *
Can be overridden in subclasses, appending a session id or the like
+ * in a redirect-specific fashion. For general URL encoding rules,
+ * override the common {@link #encodeURL} method instead, applying
+ * to redirect URLs as well as to general URLs.
+ */
+ @Override
+ public String encodeRedirectURL(String url) {
+ return encodeURL(url);
+ }
+
+ @Override
+ @Deprecated
+ public String encodeUrl(String url) {
+ return encodeURL(url);
+ }
+
+ @Override
+ @Deprecated
+ public String encodeRedirectUrl(String url) {
+ return encodeRedirectURL(url);
+ }
+
+ @Override
+ public void sendError(int status, String errorMessage) throws UnsupportedEncodingException {
+ Assert.state(!isCommitted(), "Cannot set error status - response is already committed");
+ this.status = status;
+ getWriter().println(errorMessage);
+ setCommitted(true);
+ }
+
+ @Override
+ public void sendError(int status) {
+ Assert.state(!isCommitted(), "Cannot set error status - response is already committed");
+ this.status = status;
+ setCommitted(true);
+ }
+
+ @Override
+ public void sendRedirect(String url) {
+ Assert.state(!isCommitted(), "Cannot send redirect - response is already committed");
+ Assert.notNull(url, "Redirect URL must not be null");
+ setHeader(HttpHeaders.LOCATION, url);
+ setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ setCommitted(true);
+ }
+
+
+ @Override
+ public void setDateHeader(String name, long value) {
+ setHeaderValue(name, formatDate(value));
+ }
+
+ @Override
+ public void addDateHeader(String name, long value) {
+ addHeaderValue(name, formatDate(value));
+ }
+
+
+ private String formatDate(long date) {
+ return newDateFormat().format(new Date(date));
+ }
+
+ private DateFormat newDateFormat() {
+ SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
+ dateFormat.setTimeZone(GMT);
+ return dateFormat;
+ }
+
+ @Override
+ public void setHeader(String name, @Nullable String value) {
+ setHeaderValue(name, value);
+ }
+
+ @Override
+ public void addHeader(String name, @Nullable String value) {
+ addHeaderValue(name, value);
+ }
+
+ @Override
+ public void setIntHeader(String name, int value) {
+ setHeaderValue(name, value);
+ }
+
+ @Override
+ public void addIntHeader(String name, int value) {
+ addHeaderValue(name, value);
+ }
+
+ private void setHeaderValue(String name, @Nullable Object value) {
+ if (value == null) {
+ return;
+ }
+ boolean replaceHeader = true;
+ if (setSpecialHeader(name, value, replaceHeader)) {
+ return;
+ }
+ doAddHeaderValue(name, value, replaceHeader);
+ }
+
+ private void addHeaderValue(String name, @Nullable Object value) {
+ if (value == null) {
+ return;
+ }
+ boolean replaceHeader = false;
+ if (setSpecialHeader(name, value, replaceHeader)) {
+ return;
+ }
+ doAddHeaderValue(name, value, replaceHeader);
+ }
+
+ private boolean setSpecialHeader(String name, Object value, boolean replaceHeader) {
+ if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)) {
+ setContentType(value.toString());
+ return true;
+ } else if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)) {
+ setContentLength(value instanceof Number ? ((Number) value).intValue() : Integer.parseInt(value.toString()));
+ return true;
+ } else if (HttpHeaders.CONTENT_LANGUAGE.equalsIgnoreCase(name)) {
+ String contentLanguages = value.toString();
+ HttpHeaders headers = new HttpHeaders();
+ headers.add(HttpHeaders.CONTENT_LANGUAGE, contentLanguages);
+ Locale language = headers.getContentLanguage();
+ setLocale(language != null ? language : Locale.getDefault());
+ // Since setLocale() sets the Content-Language header to the given
+ // single Locale, we have to explicitly set the Content-Language header
+ // to the user-provided value.
+ doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, contentLanguages, true);
+ return true;
+ } else if (HttpHeaders.SET_COOKIE.equalsIgnoreCase(name)) {
+ IntermediateCookie cookie = IntermediateCookie.parse(value.toString());
+ if (replaceHeader) {
+ setCookie(cookie);
+ } else {
+ addCookie(cookie);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void doAddHeaderValue(String name, Object value, boolean replace) {
+ Assert.notNull(value, "Header value must not be null");
+ HeaderValueHolder header = this.headers.computeIfAbsent(name, key -> new HeaderValueHolder());
+ if (replace) {
+ header.setValue(value);
+ } else {
+ header.addValue(value);
+ }
+ }
+
+ /**
+ * Set the {@code Set-Cookie} header to the supplied {@link Cookie},
+ * overwriting any previous cookies.
+ *
+ * @param cookie the {@code Cookie} to set
+ * @see #addCookie(Cookie)
+ * @since 5.1.10
+ */
+ private void setCookie(Cookie cookie) {
+ Assert.notNull(cookie, "Cookie must not be null");
+ doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), true);
+ }
+
+ @Override
+ public void setStatus(int status) {
+ if (!this.isCommitted()) {
+ this.status = status;
+ }
+ }
+
+ @Override
+ @Deprecated
+ public void setStatus(int status, String errorMessage) {
+ if (!this.isCommitted()) {
+ this.status = status;
+ try {
+ getWriter().println(errorMessage);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ public int getStatus() {
+ return this.status;
+ }
+
+
+ /**
+ * Inner class that adapts the ServletOutputStream to mark the
+ * response as committed once the buffer size is exceeded.
+ */
+ private class ResponseServletOutputStream extends DelegatingServletOutputStream {
+
+ public ResponseServletOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ super.write(b);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ super.flush();
+ setCommitted(true);
+ }
+ }
+
+ /**
+ * Inner class that adapts the PrintWriter to mark the
+ * response as committed once the buffer size is exceeded.
+ */
+ private class ResponsePrintWriter extends PrintWriter {
+
+ public ResponsePrintWriter(Writer out) {
+ super(out, true);
+ }
+
+ @Override
+ public void write(char[] buf, int off, int len) {
+ super.write(buf, off, len);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ @Override
+ public void write(String s, int off, int len) {
+ super.write(s, off, len);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ @Override
+ public void write(int c) {
+ super.write(c);
+ super.flush();
+ setCommittedIfBufferSizeExceeded();
+ }
+
+ @Override
+ public void flush() {
+ super.flush();
+ setCommitted(true);
+ }
+
+ @Override
+ public void close() {
+ super.flush();
+ super.close();
+ setCommitted(true);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java
index 95a5fd78..1cfd9bad 100644
--- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java
+++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/categories/CategoryWebScript1.java
@@ -1,44 +1,33 @@
package eu.xenit.apix.rest.v1.categories;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript;
+import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication;
+import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction;
+import com.gradecak.alfresco.mvc.annotation.AuthenticationType;
import eu.xenit.apix.categories.Category;
import eu.xenit.apix.categories.ICategoryService;
import eu.xenit.apix.data.QName;
import eu.xenit.apix.rest.v1.ApixV1Webscript;
-import eu.xenit.apix.rest.v1.RestV1Config;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import java.io.IOException;
import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.extensions.webscripts.WebScriptResponse;
-import org.springframework.stereotype.Component;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
-@WebScript(baseUri = RestV1Config.BaseUrl + "/category", families = RestV1Config.Family, defaultFormat = "json",
- description = "Retrieves Category information", value = "Category")
-@Authentication(AuthenticationType.USER)
-@Component("eu.xenit.apix.rest.v1.categories.CategoryWebScript1")
+@AlfrescoAuthentication(AuthenticationType.USER)
+@RestController
public class CategoryWebScript1 extends ApixV1Webscript {
- Logger logger = LoggerFactory.getLogger(CategoryWebScript1.class);
- @Autowired
- private ICategoryService categoryService;
+ private final ICategoryService categoryService;
- @Uri(value = "/aspect/{qname}", method = HttpMethod.GET)
- @ApiOperation(value = "Return the categories available for an aspect", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Categories.class))
- public void getCategoriesForAspect(@UriVariable final String qname, WebScriptResponse webScriptResponse)
- throws IOException {
+ public CategoryWebScript1(ICategoryService categoryService) {
+ this.categoryService = categoryService;
+ }
+
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/category/aspect/{qname}")
+ public ResponseEntity getCategoriesForAspect(@PathVariable final String qname) {
QName apixQName = new QName(qname);
List categories = categoryService.getCategoryTree(apixQName);
- writeJsonResponse(webScriptResponse, new Categories(categories));
+ return writeJsonResponse(new Categories(categories));
}
}
diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java
index 2da850c0..ca9377de 100644
--- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java
+++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/configuration/ConfigurationWebscript1.java
@@ -3,73 +3,59 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.ExceptionHandler;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript;
-import com.sun.star.auth.InvalidArgumentException;
+import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication;
+import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction;
+import com.gradecak.alfresco.mvc.annotation.AuthenticationType;
+import com.gradecak.alfresco.mvc.webscript.DispatcherWebscript;
import eu.xenit.apix.configuration.ConfigurationFileFlags;
import eu.xenit.apix.configuration.ConfigurationService;
import eu.xenit.apix.configuration.Configurations;
-import eu.xenit.apix.content.IContentService;
-import eu.xenit.apix.filefolder.IFileFolderService;
-import eu.xenit.apix.node.INodeService;
import eu.xenit.apix.rest.v1.ApixV1Webscript;
-import eu.xenit.apix.rest.v1.RestV1Config;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Arrays;
-import java.util.List;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.extensions.webscripts.WebScriptRequest;
-import org.springframework.extensions.webscripts.WebScriptResponse;
-import org.springframework.stereotype.Component;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.lang.Nullable;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
-@WebScript(baseUri = RestV1Config.BaseUrl, families = RestV1Config.Family, defaultFormat = "json",
- description = "Retrieves configuration data files from the datadictionary", value = "Configuration")
-@Authentication(AuthenticationType.USER)
-@Component("eu.xenit.apix.rest.v1.configuration.ConfigurationWebscript1")
+@AlfrescoAuthentication(AuthenticationType.USER)
+@RestController
public class ConfigurationWebscript1 extends ApixV1Webscript {
private static final Logger log = LoggerFactory.getLogger(ConfigurationWebscript1.class);
- @Autowired
- IFileFolderService fileFolderService;
-
- @Autowired
- INodeService nodeService;
+ private final ObjectMapper mapper;
- @Autowired
- IContentService contentService;
- @Autowired
- ConfigurationService configurationService;
+ private final ConfigurationService configurationService;
+ public ConfigurationWebscript1(
+ @Qualifier("eu.xenit.apix.configuration.ConfigurationService") ConfigurationService configurationService) {
+ this.configurationService = configurationService;
+ mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
+ }
- @Uri(value = "/configuration", method = HttpMethod.GET, defaultFormat = "json")
-
- @ApiOperation("Returns configuration files information and content")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Configurations.class))
-
- public void getConfigurationFiles(
- @RequestParam(defaultValue = "content,nodeRef", delimiter = ",") @ApiParam(value = "Comma separated field names to include.", defaultValue = "content,nodeRef", allowableValues = "content,nodeRef,path,metadata,parsedContent") String[] fields,
- @RequestParam @ApiParam("The directory to search for configuration files, relative to the data dictionary") String searchDirectory,
- @RequestParam(value = "filter.name", required = false) @ApiParam(name = "filter.name", value = "Regular expression that the node name should match.") String nameFilter,
- @RequestParam(required = false) @ApiParam("Javascript callback function") String callback,
- WebScriptRequest webScriptRequest,
- WebScriptResponse webScriptResponse
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/configuration", produces = {"application/js", MediaType.APPLICATION_JSON_VALUE})
+ public ResponseEntity> getJsConfigurationFiles(
+ @RequestParam(defaultValue = "content,nodeRef", required = false) String[] fields,
+ @RequestParam String searchDirectory,
+ @RequestParam(value = "filter.name", required = false) String nameFilter,
+ @RequestParam(required = false) String callback, final HttpServletRequest req
) throws IOException {
+ final WebScriptRequest wsReq = ((DispatcherWebscript.WebscriptRequestWrapper) req).getWebScriptServletRequest();
List fieldsList = Arrays.asList(fields);
ConfigurationFileFlags configurationFileFlags = new ConfigurationFileFlags(
fieldsList.contains("content"),
@@ -79,35 +65,36 @@ public void getConfigurationFiles(
fieldsList.contains("nodeRef"));
Configurations configurations = configurationService
.getConfigurationFiles(searchDirectory, nameFilter, configurationFileFlags);
-
- if (webScriptRequest.getFormat().equalsIgnoreCase("js")) {
- writeJsResponse(callback, webScriptResponse, configurations);
- } else {
- writeJsonResponse(webScriptResponse, configurations);
+ if ("js".equalsIgnoreCase(wsReq.getFormat()) ||
+ "js".equalsIgnoreCase(
+ getAcceptSubType(
+ req.getHeader("Accept")))) {
+ return ResponseEntity.ok()
+ .contentType(new MediaType("application", "js"))
+ .body(
+ String.format("%s(%s)", callback,
+ mapper.writeValueAsString(configurations)));
}
+ return ResponseEntity.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(configurations);
}
- private void writeJsResponse(String callback, WebScriptResponse webScriptResponse, Configurations configurations)
- throws IOException {
- webScriptResponse.setContentType("application/js");
- webScriptResponse.setContentEncoding("utf-8");
- webScriptResponse.setHeader("Cache-Control", "no-cache");
- Writer writer = webScriptResponse.getWriter();
- writer.write(callback);
- writer.write("(");
- ObjectMapper mapper = new ObjectMapper();
- mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- mapper.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
- mapper.writeValue(writer, configurations);
- writer.write(");");
- writer.flush();
- writer.close();
+ @Nullable
+ private static String getAcceptSubType(String accept) {
+ String acceptSubType = null;
+ if (accept != null) {
+ String[] acceptSplit = accept.split("/");
+ if (acceptSplit.length > 1) {
+ acceptSubType = acceptSplit[1];
+ }
+ }
+ return acceptSubType;
}
@ExceptionHandler(IllegalArgumentException.class)
- private void writeBadRequestResponse(IllegalArgumentException exception, WebScriptResponse response) throws IOException{
- log.debug("Bad input;", exception);
- response.setStatus(400);
- writeJsonResponse(response, exception.getMessage());
+ private ResponseEntity> writeBadRequestResponse(IllegalArgumentException exception) {
+ log.debug("Bad input", exception);
+ return ResponseEntity.badRequest().body(exception.getMessage());
}
}
diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java
index 61904866..7f1551c7 100644
--- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java
+++ b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/dictionary/DictionaryWebScript1.java
@@ -1,13 +1,8 @@
package eu.xenit.apix.rest.v1.dictionary;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.Authentication;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.AuthenticationType;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.FormatStyle;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.HttpMethod;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.RequestParam;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.Uri;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.UriVariable;
-import com.github.dynamicextensionsalfresco.webscripts.annotations.WebScript;
+import com.gradecak.alfresco.mvc.annotation.AlfrescoAuthentication;
+import com.gradecak.alfresco.mvc.annotation.AlfrescoTransaction;
+import com.gradecak.alfresco.mvc.annotation.AuthenticationType;
import eu.xenit.apix.data.QName;
import eu.xenit.apix.dictionary.IDictionaryService;
import eu.xenit.apix.dictionary.aspects.AspectDefinition;
@@ -18,109 +13,93 @@
import eu.xenit.apix.properties.Properties;
import eu.xenit.apix.properties.PropertyDefinition;
import eu.xenit.apix.rest.v1.ApixV1Webscript;
-import eu.xenit.apix.rest.v1.RestV1Config;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
-import java.io.IOException;
-import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.extensions.webscripts.WebScriptResponse;
-import org.springframework.stereotype.Component;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
-@WebScript(baseUri = RestV1Config.BaseUrl + "/dictionary", families = RestV1Config.Family, defaultFormat = "json",
- description = "Retrieves Dictionary information", value = "Dictionary")
-@Authentication(AuthenticationType.USER)
-@Component("eu.xenit.apix.rest.v1.property.DictionaryWebScript1")
+import javax.servlet.http.HttpServletRequest;
+
+@AlfrescoAuthentication(AuthenticationType.USER)
+@RestController
public class DictionaryWebScript1 extends ApixV1Webscript {
- Logger logger = LoggerFactory.getLogger(DictionaryWebScript1.class);
- @Autowired
- IDictionaryService dictionaryService;
+ private static final Logger logger = LoggerFactory.getLogger(DictionaryWebScript1.class);
+ private final IDictionaryService dictionaryService;
+ public DictionaryWebScript1(
+ @Qualifier(("eu.xenit.apix.dictionary.IDictionaryService")) IDictionaryService dictionaryService) {
+ this.dictionaryService = dictionaryService;
+ }
- @Uri(value = "/properties/{qname}", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Return the definition of a property", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = PropertyDefinition.class))
- public void getPropertyDefinition(@UriVariable final String qname, WebScriptResponse webScriptResponse)
- throws IOException {
- eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qname);
- PropertyDefinition propDef = dictionaryService.GetPropertyDefinition(apixQName);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/properties/**")
+ public ResponseEntity> getPropertyDefinition(HttpServletRequest request) {
+ QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/properties/");
+ PropertyDefinition propDef = dictionaryService.GetPropertyDefinition(qname);
if (propDef == null) {
- webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND);
+ return ResponseEntity.notFound().build();
}
- writeJsonResponse(webScriptResponse, propDef);
+ return writeJsonResponse(propDef);
}
-
- @Uri(value = "/properties", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Return properties", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Properties.class))
- public void getProperties(
- WebScriptResponse webScriptResponse) throws IOException {
- Properties properties = dictionaryService.getProperties();
- writeJsonResponse(webScriptResponse, properties);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/properties")
+ public ResponseEntity getProperties() {
+ return writeJsonResponse(dictionaryService.getProperties());
}
-
- @Uri(value = "/types", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Return the definitions of types", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Types.class))
- public void getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) final String parent,
- WebScriptResponse webScriptResponse) throws IOException {
- QName apixQName = new QName(parent);
- Types types = dictionaryService.GetSubTypeDefinitions(apixQName, true);
- writeJsonResponse(webScriptResponse, types);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/types")
+ public ResponseEntity getSubTypeDefinitions(@RequestParam(defaultValue = "sys:base", required = false) final String parent) {
+ return writeJsonResponse(
+ dictionaryService.GetSubTypeDefinitions(
+ new QName(parent), true
+ )
+ );
}
- @Uri(value = "/types/{qname}", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Return the definition of a type", notes = "")
- @ApiResponses({
- @ApiResponse(code = 200, message = "Success", response = TypeDefinition.class),
- @ApiResponse(code = 404, message = "Not Found")})
- public void getTypeDefinition(@UriVariable final String qname, WebScriptResponse webScriptResponse)
- throws IOException {
- logger.debug("Received type qname %s", qname);
- eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qname);
- TypeDefinition classDef = dictionaryService.GetTypeDefinition(apixQName);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/types/**")
+ public ResponseEntity> getTypeDefinition(HttpServletRequest request) {
+ QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/types/");
+ logger.debug("Received type qname {}", qname);
+ TypeDefinition classDef = dictionaryService.GetTypeDefinition(qname);
if (classDef == null) {
- webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND);
+ return ResponseEntity.notFound().build();
}
- writeJsonResponse(webScriptResponse, classDef);
+ return writeJsonResponse(classDef);
}
- @Uri(value = "/aspects/{qname}", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Return the definition of a aspect", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = AspectDefinition.class))
- public void getAspectDefinition(@UriVariable final String qname, WebScriptResponse webScriptResponse)
- throws IOException {
- logger.debug("Received aspect qname %s", qname);
- eu.xenit.apix.data.QName apixQName = new eu.xenit.apix.data.QName(qname);
- AspectDefinition classDef = dictionaryService.GetAspectDefinition(apixQName);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/aspects/**")
+ public ResponseEntity> getAspectDefinition(HttpServletRequest request) {
+ QName qname = extractQNameFromUrlPath(request, "/v1/dictionary/aspects/");
+ logger.debug("Received aspect qname {}", qname);
+ AspectDefinition classDef = dictionaryService.GetAspectDefinition(qname);
if (classDef == null) {
- webScriptResponse.setStatus(HttpStatus.SC_NOT_FOUND);
+ return ResponseEntity.notFound().build();
}
- writeJsonResponse(webScriptResponse, classDef);
+ return writeJsonResponse(classDef);
}
-
- @Uri(value = "/aspects", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Return apects", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Aspects.class))
- public void getAspects(WebScriptResponse webScriptResponse) throws IOException {
- Aspects aspects = dictionaryService.getAspects();
- writeJsonResponse(webScriptResponse, aspects);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/aspects")
+ public ResponseEntity getAspects() {
+ return writeJsonResponse(dictionaryService.getAspects());
}
- @Uri(value = "/namespaces", method = HttpMethod.GET, formatStyle = FormatStyle.ARGUMENT)
- @ApiOperation(value = "Returns the namespaces", notes = "")
- @ApiResponses(@ApiResponse(code = 200, message = "Success", response = Namespaces.class))
- public void getNamespaces(WebScriptResponse webScriptResponse) throws IOException {
- Namespaces namespaces = dictionaryService.getNamespaces();
- writeJsonResponse(webScriptResponse, namespaces);
+ @AlfrescoTransaction(readOnly = true)
+ @GetMapping(value = "/v1/dictionary/namespaces")
+ public ResponseEntity getNamespaces() {
+ return writeJsonResponse(dictionaryService.getNamespaces());
}
-
+ private QName extractQNameFromUrlPath(HttpServletRequest request, String path) {
+ String qnameValue = request.getRequestURI().split(request.getContextPath() + path)[1];
+ return new QName(qnameValue);
+ }
}
diff --git a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java b/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java
deleted file mode 100644
index bf04c99e..00000000
--- a/apix-rest-v1/src/main/java/eu/xenit/apix/rest/v1/internal/ApixArgumentResolver.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package eu.xenit.apix.rest.v1.internal;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.dynamicextensionsalfresco.webscripts.arguments.ArgumentResolver;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.extensions.webscripts.WebScriptRequest;
-import org.springframework.extensions.webscripts.WebScriptResponse;
-import org.springframework.stereotype.Component;
-
-/**
- * Created by Michiel Huygen on 14/03/2016.
- */
-@Component
-public class ApixArgumentResolver implements ArgumentResolver