Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@
<groupId>se.simonsoft</groupId>
<artifactId>cms-reporting</artifactId>
<version>2.2.1</version>
<exclusions>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</exclusion>
</exclusions>
</dependency>


Expand Down Expand Up @@ -85,7 +79,23 @@
<version>3.1.3</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<!-- Needed for Java 17 compatibility. -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<argLine>
--add-opens java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (C) 2009-2017 Simonsoft Nordic AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.simonsoft.cms.transform.command;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.simonsoft.cms.item.CmsItemId;
import se.simonsoft.cms.item.CmsRepository;
import se.simonsoft.cms.item.command.ExternalCommandHandler;
import se.simonsoft.cms.transform.config.databind.TransformImportOptions;
import se.simonsoft.cms.transform.service.TransformService;

import java.util.Map;

public class TransformImportCommandHandler implements ExternalCommandHandler<TransformImportOptions> {

private final Logger logger = LoggerFactory.getLogger(TransformImportCommandHandler.class);
private final Map<CmsRepository, TransformService> transformServiceMap;

@Inject
public TransformImportCommandHandler(Map<CmsRepository, TransformService> transformServiceMap) {
this.transformServiceMap = transformServiceMap;
}

@Override
public String handleExternalCommand(CmsItemId item, TransformImportOptions arguments) {

logger.info("Starting import for item: {} from URL: {}", item.getLogicalId(), arguments.getUrl());

try {
transformServiceMap.get(item.getRepository()).importItem(item, arguments);
String successMessage = "Import completed successfully for item: " + item.getLogicalId();
logger.info(successMessage);
return successMessage;

} catch (Exception e) {
String errorMessage = "Import failed for item: " + item.getLogicalId() + " - " + e.getMessage();
logger.error(errorMessage, e);
throw new RuntimeException(errorMessage, e);
}
}

@Override
public Class<TransformImportOptions> getArgumentsClass() {
return TransformImportOptions.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright (C) 2009-2017 Simonsoft Nordic AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.simonsoft.cms.transform.config.databind;

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import se.simonsoft.cms.item.properties.CmsItemPropertiesMap;

@JsonIgnoreProperties(ignoreUnknown = true) // Allow future changes.
public class TransformImportOptions {

// NOTE: This class is equivalent to TransformConfigOptions, but for import (external data) instead of transform (already committed).

/*
* The itemId is a separate parameter.
*
* Folder:
* - The itemId is the folder where the item should be imported.
* - The folder must be configured with auto-naming when importing non-XML.
* - The folder can be configured with auto-naming when importing XML (with or without XSL transform).
* - A folder with auto-naming will only allow a primary output from XSL transform.
* - A folder without auto-naming will not allow a primary output from XSL transform.
*
* File:
* - The imported file will become that itemId (param 'overwrite' must be true if item already exists).
* - TBD: Will additional output be allowed from XSL transform?
*/

/*
* Params:
* - 'comment': History comment for the commit.
* - 'overwrite': Must be true in order to allow overwriting an existing item in CMS.
*
* - Future: 'TransformNN'
*/
private Map <String, String> params = new HashMap<>();
private String url; // Typically an http / https url, no authentication required. Redirects must be followed.
private String content; // Content to import, typically XML or JSON.
private Map <String, String> properties = new HashMap<>(); // Properties to set on the item.
private Map <String, String> revprops = new HashMap<>(); // TODO: Consider supporting revision properties (backend recently supports).


public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}

public CmsItemPropertiesMap getItemPropertiesMap() {
CmsItemPropertiesMap m = new CmsItemPropertiesMap();
if (getProperties() != null) {
getProperties().forEach((key, value) -> {
m.put(key, value);
});
}
return m;
}
}
114 changes: 114 additions & 0 deletions src/main/java/se/simonsoft/cms/transform/rest/TransformResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Copyright (C) 2009-2017 Simonsoft Nordic AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.simonsoft.cms.transform.rest;

import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import se.simonsoft.cms.item.CmsItemId;
import se.simonsoft.cms.item.CmsRepository;
import se.simonsoft.cms.item.impl.CmsItemIdArg;
import se.simonsoft.cms.transform.service.TransformService;
import se.simonsoft.cms.transform.config.databind.TransformImportOptions;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Path("/transform5")
public class TransformResource {

private final Logger logger = LoggerFactory.getLogger(TransformResource.class);
private final Map<CmsRepository, TransformService> transformServiceMap;
private final ObjectWriter objectWriter;
private String hostname;

private static final int MAX_CONTENT_SIZE_MB = 5;

@Inject
public TransformResource(
@Named("config:se.simonsoft.cms.hostname") String hostname,
Map<CmsRepository, TransformService> transformServiceMap,
ObjectWriter objectWriter) {
this.hostname = hostname;
this.transformServiceMap = transformServiceMap;
this.objectWriter = objectWriter;
}

@POST
@Path("api/import")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response importItem(@QueryParam("item") CmsItemIdArg item, String body) throws JsonProcessingException {

if (item == null) {
throw new IllegalArgumentException("Field 'item': required");
}

item.setHostnameOrValidate(hostname);

TransformImportOptions importOptions;

try {
ObjectMapper mapper = new ObjectMapper();
importOptions = mapper.readValue(body, TransformImportOptions.class);
} catch (JsonProcessingException e) {
logger.error("API request with invalid JSON body: {}", body, e);
throw new IllegalArgumentException("Failed to parse request body: " + e.getMessage(), e);
}

if (importOptions == null) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("{\"error\": \"Import options must be provided in request body\"}")
.build();
}

String url = importOptions.getUrl();
String content = importOptions.getContent();

if ((content != null && url != null) || (content == null && url == null)) {
throw new IllegalArgumentException("Import requires either a valid URL or content.");
} else if (content != null && content.length() > MAX_CONTENT_SIZE_MB * 1024 * 1024) {
throw new IllegalArgumentException(String.format("Largest allowed content size is %d MBs.", MAX_CONTENT_SIZE_MB));
}

try {
Map<String, Set<CmsItemId>> response = new HashMap<>();
Set<CmsItemId> items = transformServiceMap.get(item.getRepository()).importItem(item, importOptions);
response.put("items", items);
return Response.ok().entity(objectWriter.writeValueAsString(response)).build();
} catch (IllegalArgumentException e) {
logger.warn("Invalid input parameters for item: {}, importOptions: {}", item, body, e);
throw e;
} catch (Exception e) {
logger.error("Import failed for item: {}, error: {}", item, e.getMessage());
throw e;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@

import se.simonsoft.cms.item.CmsItemId;
import se.simonsoft.cms.transform.config.databind.TransformConfig;
import se.simonsoft.cms.transform.config.databind.TransformImportOptions;

import java.util.Set;

public interface TransformService {

void transform(CmsItemId item, TransformConfig config);

Set<CmsItemId> importItem(CmsItemId item, TransformImportOptions config);
}
Loading