Skip to content

Commit 3e7c4e8

Browse files
authored
Merge pull request #598 from marklogic-community/feature/bug-558
Feature/bug 558
2 parents 111806e + de2ecf6 commit 3e7c4e8

File tree

4 files changed

+287
-6
lines changed

4 files changed

+287
-6
lines changed

quick-start/src/main/java/com/marklogic/quickstart/service/EntityManagerService.java

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import com.marklogic.hub.flow.FlowType;
3636
import com.marklogic.hub.scaffold.Scaffolding;
3737
import com.marklogic.quickstart.auth.ConnectionAuthenticationToken;
38+
import com.marklogic.quickstart.listeners.DeployUserModulesListener;
39+
import com.marklogic.quickstart.listeners.ValidateListener;
3840
import com.marklogic.quickstart.model.EnvironmentConfig;
3941
import com.marklogic.quickstart.model.FlowModel;
4042
import com.marklogic.quickstart.model.PluginModel;
@@ -68,14 +70,17 @@ public class EntityManagerService {
6870
private static final String UI_LAYOUT_FILE = "entities.layout.json";
6971
private static final String PLUGINS_DIR = "plugins";
7072
private static final String ENTITIES_DIR = "entities";
71-
private static final String ENTITY_FILE_EXTENSION = ".entity.json";
73+
public static final String ENTITY_FILE_EXTENSION = ".entity.json";
7274

7375
@Autowired
7476
private FlowManagerService flowManagerService;
7577

7678
@Autowired
7779
private FileSystemWatcherService watcherService;
7880

81+
@Autowired
82+
private DataHubService dataHubService;
83+
7984
private EnvironmentConfig envConfig() {
8085
ConnectionAuthenticationToken authenticationToken = (ConnectionAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
8186
return authenticationToken.getEnvironmentConfig();
@@ -156,18 +161,50 @@ public EntityModel createEntity(String projectDir, EntityModel newEntity) throws
156161
public EntityModel saveEntity(EntityModel entity) throws IOException {
157162
JsonNode node = entity.toJson();
158163
ObjectMapper objectMapper = new ObjectMapper();
159-
String filename = entity.getFilename();
160-
if (filename == null) {
161-
String title = entity.getInfo().getTitle();
164+
String fullpath = entity.getFilename();
165+
String title = entity.getInfo().getTitle();
166+
167+
if (fullpath == null) {
162168
Path dir = Paths.get(envConfig().getProjectDir(), PLUGINS_DIR, ENTITIES_DIR, title);
163169
if (!dir.toFile().exists()) {
164170
dir.toFile().mkdirs();
165171
}
166-
filename = Paths.get(dir.toString(), title + ENTITY_FILE_EXTENSION).toString();
172+
fullpath = Paths.get(dir.toString(), title + ENTITY_FILE_EXTENSION).toString();
173+
}
174+
else {
175+
String filename = new File(fullpath).getName();
176+
String entityFromFilename = filename.substring(0, filename.indexOf(ENTITY_FILE_EXTENSION));
177+
if (!entityFromFilename.equals(entity.getName())) {
178+
// The entity name was changed since the files were created. Update
179+
// the path.
180+
181+
// Update the name of the entity definition file
182+
File origFile = new File(fullpath);
183+
File newFile = new File(origFile.getParent() + File.separator + title + ENTITY_FILE_EXTENSION);
184+
if (!origFile.renameTo(newFile)) {
185+
throw new IOException("Unable to rename " + origFile.getAbsolutePath() + " to " +
186+
newFile.getAbsolutePath());
187+
};
188+
189+
// Update the directory name
190+
File origDirectory = new File(origFile.getParent());
191+
File newDirectory = new File(origDirectory.getParent() + File.separator + title);
192+
if (!origDirectory.renameTo(newDirectory)) {
193+
throw new IOException("Unable to rename " + origDirectory.getAbsolutePath() + " to " +
194+
newDirectory.getAbsolutePath());
195+
}
196+
197+
fullpath = newDirectory.getAbsolutePath() + File.separator + title + ENTITY_FILE_EXTENSION;
198+
entity.setFilename(fullpath);
199+
200+
// Redeploy the flows
201+
dataHubService.reinstallUserModules(envConfig().getMlSettings(), null, null);
202+
}
167203
}
168204

205+
169206
String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(node);
170-
FileUtils.writeStringToFile(new File(filename), json);
207+
FileUtils.writeStringToFile(new File(fullpath), json);
171208

172209
return entity;
173210
}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package com.marklogic.quickstart.service;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.marklogic.hub.HubConfig;
6+
import com.marklogic.hub.HubTestBase;
7+
import com.marklogic.hub.flow.CodeFormat;
8+
import com.marklogic.hub.flow.DataFormat;
9+
import com.marklogic.hub.flow.FlowType;
10+
import com.marklogic.hub.scaffold.Scaffolding;
11+
import com.marklogic.hub.util.FileUtil;
12+
import com.marklogic.quickstart.auth.ConnectionAuthenticationToken;
13+
import com.marklogic.quickstart.model.EnvironmentConfig;
14+
import com.marklogic.quickstart.model.FlowModel;
15+
import com.marklogic.quickstart.model.entity_services.EntityModel;
16+
import org.apache.commons.io.FileUtils;
17+
import org.junit.*;
18+
import org.junit.runner.RunWith;
19+
import org.springframework.beans.factory.annotation.Autowired;
20+
import org.springframework.boot.test.context.SpringBootTest;
21+
import org.springframework.mock.web.MockHttpServletRequest;
22+
import org.springframework.mock.web.MockHttpSession;
23+
import org.springframework.security.core.context.SecurityContextHolder;
24+
import org.springframework.test.context.junit4.SpringRunner;
25+
26+
import java.io.IOException;
27+
import java.nio.file.Path;
28+
import java.nio.file.Paths;
29+
import java.util.List;
30+
31+
@RunWith(SpringRunner.class)
32+
@SpringBootTest()
33+
public class EntityManagerServiceTest extends HubTestBase {
34+
35+
private static String ENTITY = "test-entity";
36+
private static String ENTITY2 = "test-entity2";
37+
private static Path projectDir = Paths.get(".", PROJECT_PATH);
38+
39+
@Autowired
40+
EntityManagerService entityMgrService;
41+
42+
@BeforeClass
43+
public static void setupSuite() throws IOException {
44+
FileUtils.deleteDirectory(projectDir.toFile());
45+
46+
EnvironmentConfig envConfig = new EnvironmentConfig(projectDir.toString(), "local", "admin", "admin");
47+
envConfig.setMlSettings(HubConfig.hubFromEnvironment(projectDir.toString(), null));
48+
envConfig.checkIfInstalled();
49+
setEnvConfig(envConfig);
50+
51+
installHub();
52+
}
53+
54+
private static void setEnvConfig(EnvironmentConfig envConfig) {
55+
ConnectionAuthenticationToken authenticationToken = new ConnectionAuthenticationToken("admin", "admin", "localhost", 1, "local");
56+
authenticationToken.setEnvironmentConfig(envConfig);
57+
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
58+
}
59+
60+
@Before
61+
public void setUp() throws IOException {
62+
FileUtils.deleteDirectory(projectDir.toFile());
63+
64+
Scaffolding scaffolding = new Scaffolding(projectDir.toString(), stagingClient);
65+
scaffolding.createEntity(ENTITY);
66+
scaffolding.createFlow(ENTITY, "sjs-json-input-flow", FlowType.INPUT,
67+
CodeFormat.JAVASCRIPT, DataFormat.JSON);
68+
69+
scaffolding.createFlow(ENTITY, "sjs-xml-input-flow", FlowType.INPUT,
70+
CodeFormat.JAVASCRIPT, DataFormat.XML);
71+
72+
scaffolding.createFlow(ENTITY, "xqy-json-input-flow", FlowType.INPUT,
73+
CodeFormat.XQUERY, DataFormat.JSON);
74+
75+
scaffolding.createFlow(ENTITY, "xqy-xml-input-flow", FlowType.INPUT,
76+
CodeFormat.XQUERY, DataFormat.XML);
77+
78+
Path entityDir = projectDir.resolve("plugins/entities/" + ENTITY);
79+
Path inputDir = entityDir.resolve("input");
80+
81+
String entityFilename = ENTITY + EntityManagerService.ENTITY_FILE_EXTENSION;
82+
FileUtil.copy(getResourceStream(entityFilename), entityDir.resolve(entityFilename).toFile());
83+
84+
FileUtil.copy(getResourceStream("flow-manager/sjs-flow/headers.sjs"), inputDir.resolve("sjs-json-input-flow/headers.sjs").toFile());
85+
FileUtil.copy(getResourceStream("flow-manager/sjs-flow/content-input.sjs"), inputDir.resolve("sjs-json-input-flow/content.sjs").toFile());
86+
FileUtil.copy(getResourceStream("flow-manager/sjs-flow/triples.sjs"), inputDir.resolve("sjs-json-input-flow/triples.sjs").toFile());
87+
88+
FileUtil.copy(getResourceStream("flow-manager/sjs-flow/headers.sjs"), inputDir.resolve("sjs-xml-input-flow/headers.sjs").toFile());
89+
FileUtil.copy(getResourceStream("flow-manager/sjs-flow/content-input.sjs"), inputDir.resolve("sjs-xml-input-flow/content.sjs").toFile());
90+
FileUtil.copy(getResourceStream("flow-manager/sjs-flow/triples.sjs"), inputDir.resolve("sjs-xml-input-flow/triples.sjs").toFile());
91+
92+
FileUtil.copy(getResourceStream("flow-manager/xqy-flow/headers-json.xqy"), inputDir.resolve("xqy-json-input-flow/headers.xqy").toFile());
93+
FileUtil.copy(getResourceStream("flow-manager/xqy-flow/content-input.xqy"), inputDir.resolve("xqy-json-input-flow/content.xqy").toFile());
94+
FileUtil.copy(getResourceStream("flow-manager/xqy-flow/triples.xqy"), inputDir.resolve("xqy-json-input-flow/triples.xqy").toFile());
95+
96+
FileUtil.copy(getResourceStream("flow-manager/xqy-flow/headers-xml.xqy"), inputDir.resolve("xqy-xml-input-flow/headers.xqy").toFile());
97+
FileUtil.copy(getResourceStream("flow-manager/xqy-flow/content-input.xqy"), inputDir.resolve("xqy-xml-input-flow/content.xqy").toFile());
98+
FileUtil.copy(getResourceStream("flow-manager/xqy-flow/triples.xqy"), inputDir.resolve("xqy-xml-input-flow/triples.xqy").toFile());
99+
100+
getDataHub().installUserModules(true);
101+
}
102+
103+
@AfterClass
104+
public static void tearDown() throws IOException {
105+
FileUtils.deleteDirectory(projectDir.toFile());
106+
uninstallHub();
107+
}
108+
109+
@Test
110+
public void getEntities() throws IOException {
111+
List<EntityModel> entities = entityMgrService.getEntities();
112+
113+
Assert.assertEquals(1, entities.size());
114+
Assert.assertEquals(ENTITY, entities.get(0).getName());
115+
}
116+
117+
@Test
118+
public void saveEntity() throws IOException {
119+
Path entityDir = projectDir.resolve("plugins/entities/" + ENTITY);
120+
String entityFilename = ENTITY2 + EntityManagerService.ENTITY_FILE_EXTENSION;
121+
122+
JsonNode node = getJsonFromResource(entityFilename);
123+
124+
EntityModel entity = EntityModel.fromJson(entityFilename, node);
125+
entity.setFilename(entityDir.resolve(entityFilename).toString());
126+
127+
entityMgrService.saveEntity(entity);
128+
129+
List<EntityModel> entities = entityMgrService.getEntities();
130+
131+
Assert.assertEquals(2, entities.size());
132+
String[] expected = {ENTITY, ENTITY2};
133+
String[] actual = { entities.get(0).getName(), entities.get(1).getName() };
134+
Assert.assertArrayEquals(expected, actual);
135+
}
136+
137+
@Test
138+
public void getEntity() throws IOException {
139+
EntityModel entity = entityMgrService.getEntity(ENTITY);
140+
141+
Assert.assertEquals(ENTITY, entity.getName());
142+
Assert.assertEquals(4, entity.getInputFlows().size());
143+
Assert.assertEquals(0, entity.getHarmonizeFlows().size());
144+
}
145+
146+
@Test public void getNoSuchEntity() throws IOException {
147+
EntityModel entity = entityMgrService.getEntity("no-such-entity");
148+
149+
Assert.assertNull(entity);
150+
}
151+
152+
@Test
153+
public void getFlow() throws IOException {
154+
final String FLOW_NAME = "sjs-json-input-flow";
155+
FlowModel flow = entityMgrService.getFlow(ENTITY, FlowType.INPUT, FLOW_NAME);
156+
Assert.assertEquals(ENTITY, flow.entityName);
157+
Assert.assertEquals(FLOW_NAME, flow.flowName);
158+
Assert.assertEquals(FlowType.INPUT, flow.flowType);
159+
}
160+
161+
@Test
162+
public void getNoSuchFlow() throws IOException {
163+
final String FLOW_NAME = "no-such-flow";
164+
FlowModel flow = entityMgrService.getFlow(ENTITY, FlowType.INPUT, FLOW_NAME);
165+
Assert.assertNull(flow);
166+
}
167+
168+
/**
169+
* Try getting a flow using the name of a valid flow, but requesting using the wrong type.
170+
* @throws IOException
171+
*/
172+
@Test
173+
public void getFlowByWrongType() throws IOException {
174+
final String FLOW_NAME = "sjs-json-input-flow";
175+
FlowModel flow = entityMgrService.getFlow(ENTITY, FlowType.HARMONIZE, FLOW_NAME);
176+
Assert.assertNull(flow);
177+
}
178+
179+
/**
180+
* Addresses https://github.com/marklogic-community/marklogic-data-hub/issues/558.
181+
*/
182+
@Test
183+
public void changeEntityName() throws IOException {
184+
final String RENAMED_ENTITY = "renamed-entity";
185+
186+
// Get the original entity
187+
EntityModel entity = entityMgrService.getEntity(ENTITY);
188+
189+
// Convert to String and change the title (the UI just changes the title property)
190+
String strEntity = entity.toJson().toString();
191+
strEntity = strEntity.replaceFirst("\"title\"\\s*:\\s*\"test-entity\"", "\"title\" : \"" + RENAMED_ENTITY + "\"");
192+
strEntity = strEntity.replaceFirst("\"test-entity\"\\s*:", "\"" + RENAMED_ENTITY + "\" :");
193+
194+
// Convert back to JsonNode
195+
ObjectMapper mapper = new ObjectMapper();
196+
JsonNode renamed = mapper.readTree(strEntity);
197+
EntityModel renamedEntity = EntityModel.fromJson(entity.getFilename(), renamed);
198+
199+
// Save the renamedEntity
200+
entityMgrService.saveEntity(renamedEntity);
201+
202+
List<EntityModel> entities = entityMgrService.getEntities();
203+
Assert.assertEquals(1, entities.size());
204+
205+
// Load the entity, then check the flows to make sure they know the right entity name
206+
final String FLOW_NAME = "sjs-json-input-flow";
207+
List<FlowModel> inputFlows = entities.get(0).getInputFlows();
208+
209+
Assert.assertEquals(RENAMED_ENTITY, inputFlows.get(0).entityName);
210+
Assert.assertEquals(FLOW_NAME, inputFlows.get(0).flowName);
211+
Assert.assertEquals(FlowType.INPUT, inputFlows.get(0).flowType);
212+
213+
}
214+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"info" : {
3+
"title" : "test-entity",
4+
"version" : "0.0.1"
5+
},
6+
"definitions" : {
7+
"test-entity" : {
8+
"required" : [ ],
9+
"rangeIndex" : [ ],
10+
"wordLexicon" : [ ],
11+
"properties" : {
12+
}
13+
}
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"info" : {
3+
"title" : "test-entity2",
4+
"version" : "0.0.1"
5+
},
6+
"definitions" : {
7+
"test-entity2" : {
8+
"required" : [ ],
9+
"rangeIndex" : [ ],
10+
"wordLexicon" : [ ],
11+
"properties" : {
12+
}
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)