Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

From version 5/fix issue 769 hg 5463 auto set propertyid #772

Open
wants to merge 1 commit into
base: version-5
Choose a base branch
from
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
19 changes: 18 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,30 @@ target/
.classpath
.project
.settings/
**/.factorypath
out/

# https://www.jenv.be/
.java-version

logs/

velocity.log.*
*.log

dependency-reduced-pom.xml

.protegedata/
.protegedata/

# Package Files
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.google.gwt.resources.client.DataResource;
import edu.stanford.bmir.protege.web.client.dispatch.DispatchServiceManager;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;
import edu.stanford.bmir.protege.web.server.util.TypelessJSONSerialization;

import javax.annotation.Nonnull;
import javax.inject.Inject;
Expand Down Expand Up @@ -31,10 +32,12 @@ public ProjectSettingsService(DispatchServiceManager dispatch, ProjectId project
public void importSettings(@Nonnull String settingsToImportJson,
@Nonnull Runnable importSuccessfulHandler,
@Nonnull Runnable importErrorHandler) {
String settingsJsonWithUpdatedProjectId;
try {
settingsJsonWithUpdatedProjectId = updateInputJSONProjectId(settingsToImportJson);
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.POST, "/data/projects/" + projectId.getId() + "/settings");

requestBuilder.setRequestData(settingsToImportJson);
requestBuilder.setRequestData(settingsJsonWithUpdatedProjectId);
requestBuilder.setHeader("Content-Type", "application/json");
requestBuilder.setCallback(new RequestCallback() {
@Override
Expand All @@ -57,5 +60,9 @@ public void onError(Request request, Throwable exception) {
importErrorHandler.run();
}
}

private String updateInputJSONProjectId(@Nonnull String settingsToImportJson) {
return TypelessJSONSerialization.resplaceAllStringValue(settingsToImportJson, "projectId", this.projectId.getId());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@
import org.semanticweb.owlapi.model.*;
import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;

import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Provider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Matthew Horridge
* Stanford Center for Biomedical Informatics Research
Expand All @@ -26,7 +31,11 @@ public class ObjectMapperProvider implements Provider<ObjectMapper> {

@Nonnull
private final OWLDataFactory dataFactory;

private static Logger logger = LoggerFactory.getLogger(ObjectMapperProvider.class);

private static AtomicInteger mapperInstanceCount = new AtomicInteger();

@Inject
public ObjectMapperProvider() {
this.dataFactory = new OWLDataFactoryImpl();
Expand All @@ -35,6 +44,9 @@ public ObjectMapperProvider() {
@Override
public ObjectMapper get() {
ObjectMapper mapper = new ObjectMapper();
int instanceCount = mapperInstanceCount.incrementAndGet();
String msg = String.format("Instantiated another ObjectMappger#%08x, total: %d", mapper.hashCode(), instanceCount);
logger.info(msg);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setDefaultPrettyPrinter(new DefaultPrettyPrinter());
mapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
package edu.stanford.bmir.protege.web.server.tag;

import com.google.common.collect.Streams;
import edu.stanford.bmir.protege.web.server.events.HasPostEvents;
import edu.stanford.bmir.protege.web.shared.event.ProjectEvent;
import edu.stanford.bmir.protege.web.shared.inject.ProjectSingleton;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;
import edu.stanford.bmir.protege.web.shared.tag.*;
import org.semanticweb.owlapi.model.OWLEntity;
import static com.google.common.base.Preconditions.checkNotNull;
import static edu.stanford.bmir.protege.web.shared.tag.TagId.createTagId;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkNotNull;
import static edu.stanford.bmir.protege.web.shared.tag.TagId.createTagId;
import static java.util.stream.Collectors.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;

import org.semanticweb.owlapi.model.OWLEntity;

import com.google.common.collect.Streams;

import edu.stanford.bmir.protege.web.server.events.HasPostEvents;
import edu.stanford.bmir.protege.web.shared.event.ProjectEvent;
import edu.stanford.bmir.protege.web.shared.inject.ProjectSingleton;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;
import edu.stanford.bmir.protege.web.shared.tag.EntityTagsChangedEvent;
import edu.stanford.bmir.protege.web.shared.tag.ProjectTagsChangedEvent;
import edu.stanford.bmir.protege.web.shared.tag.Tag;
import edu.stanford.bmir.protege.web.shared.tag.TagData;
import edu.stanford.bmir.protege.web.shared.tag.TagId;

/**
* Matthew Horridge
Expand Down Expand Up @@ -150,6 +166,8 @@ public Collection<Tag> getProjectTags() {
*/
public void setProjectTags(@Nonnull Collection<TagData> newProjectTags) {
checkNotNull(newProjectTags);
if (newProjectTags.size() == 0)
return;
Collection<Tag> currentProjectTags = getProjectTags();
Set<OWLEntity> modifiedEntityTags = new HashSet<>();
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package edu.stanford.bmir.protege.web.server.util;

public class JavaUtil {
/**
* The purpose of this cast utility to be able to suppress unchecked
* cast in one and only one place so we don't have to pollute the main
* application code with @SuppressWarnings and thus be able to flag
* places where the type cast warning(s) are/were unexpected.
* @param <T>
* @param obj
* @return
*
* This great idea came from:
* @see http://www.whizu.org/articles/how-to-avoid-unchecked-cast-warnings-with-java-generics.whizu
*/
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T)obj;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package edu.stanford.bmir.protege.web.server.util;

import static edu.stanford.bmir.protege.web.server.util.JavaUtil.cast;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;

/**
* These utility methods are for manipulating arbitrary JSON without needing to worry about what
* typed entities the JSON should be de/serialized to/from.
*
* Initial motivation is to be able to change the value of "projectId" in project settings and
* project forms import JSON.
*
* @author Chris Wolf <[email protected]>
*/
public class TypelessJSONSerialization {

// TODO: should probably be injected, but effects the whole upstream DI call chain...
// TODO: ...and plus, ObjectMapper very expensive, so should be created only once.
private static final ObjectMapper objectMapper = new ObjectMapper();

public TypelessJSONSerialization() {
}

/**
* Accepts any arbitrary JSON and deserializes to nested <code>LinkedHashMap<String, Object></code>
* instances. Note that the <code>Object</code> type parameter could be of type <code>String</code>,
* <code>List</code>, or <code>Map</code> where the latter is for arbitrary nesting levels.
*
* <b>N.B.</b> For normal, strongly typed Webprotege serialization, use the <code>ObjectMapper</code>
* obtained from <code>ObjectMapperProvider</code> from <i>webprotege-server-core</i>.
*
* @param json
* @return
* @throws IOException
*/
public static Map<String, Object> deserializeJSON(@Nonnull String json) throws IOException {
ObjectReader objectReader = objectMapper.readerFor(new TypeReference<Map<String, Object>>() {
});
return objectReader.readValue(json);
}

/**
*
* @param object
* @return
* @throws IOException
*/
public static String serializeToJSON(Map<String, Object> object) throws IOException {
return serializeToJSON(object, false);
}

public static String serializeToJSON(Map<String, Object> object, boolean prettyPrint) throws IOException {
ObjectWriter objectWriter = prettyPrint ? objectMapper.writerWithDefaultPrettyPrinter() : objectMapper.writer();
return objectWriter.writeValueAsString(object);
}

public static String resplaceAllStringValue(@Nonnull String json, @Nonnull String keyName,
@Nonnull String replacementValue) throws IOException {

Map<String, Object> deserialized = deserializeJSON(json);

walkMapAndDReplace(deserialized, keyName, replacementValue);

String serialized = serializeToJSON(deserialized);

return serialized;
}

static void walkMapAndDReplace(Map<String, Object> data, String keyName, String replacementValue) {
for (var mapEntry : data.entrySet()) {
if (mapEntry.getValue() instanceof String && mapEntry.getKey().equals(keyName)) {
mapEntry.setValue(replacementValue);
} else if (mapEntry.getValue() instanceof List) {
List<Object> objlist = cast(mapEntry.getValue());
for (Object listEntry : objlist) {
if (listEntry instanceof Map)
walkMapAndDReplace(cast(listEntry), keyName, replacementValue);
}
} else if (mapEntry.getValue() instanceof Map) {
walkMapAndDReplace(cast(mapEntry.getValue()), keyName, replacementValue);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package edu.stanford.bmir.protege.web;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

public class TestUtils {
/**
* Read contents of text file resource from <code>src/test/resources</code>.
* Entire content read into memory, so best for small files.
*
* @param resourceName
* @return text content and assuming UTF-8 encoding
* @throws IOException
*/
public static String readResourceTestFile(String resourceName) throws IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URI resource;
try {
resource = classLoader.getResource(resourceName).toURI();
} catch (URISyntaxException e) {
String msg = String.format("Can't read '%s'", resourceName);
throw new IOException(msg, e);
}
byte[] rawContent = Files.readAllBytes(Paths.get(resource));

return new String(rawContent, StandardCharsets.UTF_8);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package edu.stanford.bmir.protege.web.server.util;

import static edu.stanford.bmir.protege.web.server.util.JavaUtil.cast;
import static org.junit.Assert.assertEquals;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner.Silent;

import edu.stanford.bmir.protege.web.TestUtils;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;

@RunWith(Silent.class)
public class TypelessJSONSerialization_TestCase {
private ProjectId projectId = ProjectId.get("c4e39f8f-d2b3-4212-8888-28fabd2aa5ac");

@Test
public void testJSONSerialization() throws Exception {
// test basic round-trip deserialize/serialize

String testSettings = TestUtils
.readResourceTestFile("edu/stanford/bmir/protege/web/server/util/project_settings_notags.json");
// out.println(testSettings);
Map<String, Object> data = TypelessJSONSerialization.deserializeJSON(testSettings);

String newSettings = TypelessJSONSerialization.serializeToJSON(data, true);

assertEquals(StringUtils.deleteWhitespace(testSettings), StringUtils.deleteWhitespace(newSettings));
// out.println(newSettings);
}

@Test
public void testJSONSerializationNameValueReplacement() throws Exception {
String testSettings = TestUtils
.readResourceTestFile("edu/stanford/bmir/protege/web/server/util/project_settings_notags.json");

String newSettings = TypelessJSONSerialization.resplaceAllStringValue(testSettings, "projectId",
projectId.getId());
Map<String, Object> data = TypelessJSONSerialization.deserializeJSON(newSettings);

String id = projectId.getId();
Map<String, Object> projectSettings = cast(data.get("projectSettings"));
Map<String, Object> sharingSettings = cast(data.get("sharingSettings"));
Map<String, Object> searchSettings = cast(data.get("searchSettings"));
List<Map<String, Object>> searchFilters = cast(searchSettings.get("searchFilters"));

assertEquals(id, projectSettings.get("projectId"));
assertEquals(id, sharingSettings.get("projectId"));
assertEquals(id, searchSettings.get("projectId"));
assertEquals(id, searchFilters.get(0).get("projectId"));
}
}
Loading