1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.importexport;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.util.StringLengthComparator;
38 import info.magnolia.context.MgnlContext;
39 import info.magnolia.importexport.command.JcrExportCommand;
40 import info.magnolia.importexport.command.JcrImportCommand;
41 import info.magnolia.jcr.util.NodeNameHelper;
42 import info.magnolia.jcr.util.NodeTypes;
43 import info.magnolia.jcr.util.NodeUtil;
44 import info.magnolia.objectfactory.Components;
45 import info.magnolia.repository.DefaultRepositoryManager;
46 import info.magnolia.repository.RepositoryManager;
47
48 import java.io.File;
49 import java.io.FileOutputStream;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.Collections;
55 import java.util.Iterator;
56 import java.util.List;
57
58 import javax.jcr.Node;
59 import javax.jcr.RepositoryException;
60 import javax.jcr.Session;
61
62 import org.apache.commons.io.FilenameUtils;
63 import org.apache.commons.io.IOUtils;
64 import org.apache.commons.lang3.StringUtils;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68
69
70
71 public class BootstrapUtil {
72 private static final Logger log = LoggerFactory.getLogger(BootstrapUtil.class);
73
74 public static void bootstrap(String[] resourceNames, int importUUIDBehavior) throws IOException, RepositoryException {
75
76 List<String> list = new ArrayList<>(Arrays.asList(resourceNames));
77 if (list.contains(null)) {
78 throw new IllegalArgumentException("Resource names contain a <null> entry that cannot be processed.");
79 }
80
81 Collections.sort(list, new StringLengthComparator());
82
83 for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
84 bootstrap(iter.next(), null, importUUIDBehavior);
85 }
86 }
87
88 public static void bootstrap(String resourceName, String subPath, int importUUIDBehavior) throws IOException, RepositoryException {
89 String name = getFilenameFromResource(resourceName, null);
90 String workspace = getWorkspaceNameFromResource(resourceName);
91 String fullPath = getFullpathFromResource(resourceName);
92 if (subPath != null) {
93 fullPath += "/" + StringUtils.substringAfter(StringUtils.removeStart(StringUtils.removeEnd(subPath, "/"), "/"), "/");
94 }
95 String parentPath = StringUtils.substringBeforeLast(fullPath, "/");
96 if (StringUtils.isEmpty(parentPath)) {
97 parentPath = "/";
98 }
99
100 log.debug("Will bootstrap {}", resourceName);
101
102 final InputStream stream = BootstrapUtil.class.getResourceAsStream(resourceName);
103 if (stream == null) {
104 throw new IOException("Can't find resource to bootstrap at " + resourceName);
105 }
106
107
108 String nameOfNodeAfterTheImportedNode = null;
109
110
111 RepositoryManager repoManager = Components.getComponent(RepositoryManager.class);
112 if (repoManager instanceof DefaultRepositoryManager) {
113 boolean isClusteredWorkspace = ((DefaultRepositoryManager) repoManager).isClusteredWorkspace(workspace);
114 boolean isMasterCluster = ((DefaultRepositoryManager) repoManager).isClusterMaster();
115
116 if (isClusteredWorkspace && !isMasterCluster) {
117 log.info("Skipping bootstrapping of resource '{}' because workspace '{}' is clustered and node is not cluster master ", resourceName, workspace);
118 return;
119 }
120 }
121
122 final Session session = MgnlContext.getJCRSession(workspace);
123
124 try {
125
126 if (StringUtils.isNotEmpty(fullPath) && session.nodeExists(fullPath)) {
127
128 Node node = session.getNode(fullPath);
129 if (!NodeUtil.isLastSibling(node)) {
130 nameOfNodeAfterTheImportedNode = NodeUtil.getSiblingAfter(node).getName();
131 }
132 if (node.getDepth() == 1) {
133 Node parent = node.getParent();
134 Node tmp = NodeUtil.createPath(parent, Components.getComponent(NodeNameHelper.class).getUniqueName(parent, "tmp"), NodeTypes.Content.NAME);
135 NodeUtil.moveNode(node, tmp);
136 tmp.remove();
137 } else {
138 node.remove();
139 }
140 log.warn("Deleted already existing node for bootstrapping: {}", fullPath);
141 }
142 NodeUtil.createPath(session.getRootNode(), parentPath, NodeTypes.Content.NAME);
143
144 final JcrImportCommand command = new JcrImportCommand();
145 command.setStream(stream);
146 command.setFileName(resourceName);
147 command.setRepository(workspace);
148 command.setPath(parentPath);
149 command.setImportPath(subPath);
150 command.setIdentifierBehavior(importUUIDBehavior);
151 command.setSaveAfterImport(false);
152 command.execute(MgnlContext.getInstance());
153
154 } catch (RepositoryException e) {
155 IOUtils.closeQuietly(stream);
156 throw new RepositoryException("Can't check existence of node for bootstrap file: [" + name + "]", e);
157 } catch (Exception e) {
158 throw new RuntimeException(e);
159 }
160 if (nameOfNodeAfterTheImportedNode != null) {
161 Node newNode = session.getNode(fullPath);
162 NodeUtil.orderBefore(newNode, nameOfNodeAfterTheImportedNode);
163 }
164 }
165
166
167
168
169 public static void export(Content content, File directory) throws IOException, RepositoryException {
170 BootstrapUtil.export(content.getJCRNode(), directory);
171 }
172
173 public static void export(Node content, File directory) throws IOException, RepositoryException {
174
175 Session session = content.getSession();
176 String workspace = session.getWorkspace().getName();
177 String path = content.getPath();
178 String fileName = workspace + DataTransporter.createExportPath(path) + ".xml";
179 File file = new File(directory, fileName);
180 FileOutputStream out = new FileOutputStream(file);
181 try {
182 DataTransporter.executeExport(out, false, true, session, path, workspace, DataTransporter.XML);
183 } finally {
184 IOUtils.closeQuietly(out);
185 }
186 }
187
188
189
190
191 public static String getWorkspaceNameFromResource(final String resourcePath) {
192 String resourceName = StringUtils.replace(resourcePath, "\\", "/");
193
194 String name = getFilenameFromResource(resourceName, null);
195 String fullPath = DataTransporter.revertExportPath(name);
196 return StringUtils.substringBefore(fullPath, "/");
197 }
198
199
200
201
202 public static String getFullpathFromResource(final String resourcePath) {
203 String resourceName = StringUtils.replace(resourcePath, "\\", "/");
204
205 String name = getFilenameFromResource(resourceName, null);
206 String fullPath = DataTransporter.revertExportPath(name);
207 String repository = StringUtils.substringBefore(fullPath, "/");
208
209 return StringUtils.removeStart(fullPath, repository);
210 }
211
212
213
214
215 public static String getPathnameFromResource(final String resourcePath) {
216 String resourceName = StringUtils.replace(resourcePath, "\\", "/");
217
218 String name = getFilenameFromResource(resourceName, null);
219 String fullPath = DataTransporter.revertExportPath(name);
220 String pathName = StringUtils.substringAfter(StringUtils.substringBeforeLast(fullPath, "/"), "/");
221
222 if (!pathName.startsWith("/")) {
223 pathName = "/" + pathName;
224 }
225 return pathName;
226 }
227
228
229
230
231
232 public static String getFilenameFromResource(final String resourcePath, final String extension) {
233 String resolvedExtension = extension;
234
235 if (StringUtils.isEmpty(extension)) {
236 resolvedExtension = FilenameUtils.getExtension(resourcePath);
237 if (!JcrExportCommand.Format.isSupportedExtension(resolvedExtension)) {
238 resolvedExtension = StringUtils.EMPTY;
239 }
240 }
241 String tmpResourcePath = resourcePath;
242 if (resourcePath.contains("/")) {
243 tmpResourcePath = StringUtils.substringAfterLast(resourcePath, "/");
244 }
245 return StringUtils.removeEnd(tmpResourcePath, resolvedExtension.startsWith(".") ? resolvedExtension : "." + resolvedExtension);
246 }
247
248 }