1 package org.exoplatform.services.wcm.extensions.scheduler.impl;
2
3 import java.io.BufferedReader;
4 import java.io.ByteArrayOutputStream;
5 import java.io.File;
6 import java.io.FileOutputStream;
7 import java.io.FileReader;
8 import java.io.InputStreamReader;
9 import java.io.OutputStream;
10 import java.net.ConnectException;
11 import java.net.HttpURLConnection;
12 import java.net.URI;
13 import java.net.URL;
14 import java.sql.Timestamp;
15 import java.util.Calendar;
16 import java.util.Date;
17 import java.util.HashMap;
18 import java.util.List;
19
20 import javax.jcr.Node;
21 import javax.jcr.NodeIterator;
22 import javax.jcr.RepositoryException;
23 import javax.jcr.Session;
24 import javax.jcr.query.Query;
25 import javax.jcr.query.QueryManager;
26 import javax.jcr.query.QueryResult;
27 import javax.xml.stream.XMLOutputFactory;
28 import javax.xml.stream.XMLStreamWriter;
29
30 import org.exoplatform.services.cms.taxonomy.TaxonomyService;
31 import org.exoplatform.services.ecm.publication.PublicationPlugin;
32 import org.exoplatform.services.ecm.publication.PublicationService;
33 import org.exoplatform.services.jcr.RepositoryService;
34 import org.exoplatform.services.jcr.core.ManageableRepository;
35 import org.exoplatform.services.jcr.ext.common.SessionProvider;
36 import org.exoplatform.services.log.ExoLogger;
37 import org.exoplatform.services.log.Log;
38 import org.exoplatform.services.wcm.core.NodeLocation;
39 import org.exoplatform.services.wcm.extensions.publication.lifecycle.authoring.AuthoringPublicationConstant;
40 import org.exoplatform.services.wcm.extensions.security.SHAMessageDigester;
41 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
42 import org.quartz.Job;
43 import org.quartz.JobDataMap;
44 import org.quartz.JobExecutionContext;
45 import org.quartz.JobExecutionException;
46
47
48
49
50 public class ExportContentJob implements Job {
51 private static final Log LOG = ExoLogger.getLogger(ExportContentJob.class.getName());
52
53 private static final String MIX_TARGET_PATH = "mix:targetPath";
54
55 private static final String MIX_TARGET_WORKSPACE = "mix:targetWorkspace";
56
57 private static final String URL = "http://www.w3.org/2001/XMLSchema";
58
59 private static final String START_TIME_PROPERTY = "publication:startPublishedDate";
60
61 private String fromState = null;
62
63 private String toState = null;
64
65 private String localTempDir = null;
66
67 private String targetServerUrl = null;
68
69 private String targetKey = null;
70
71 private String predefinedPath = null;
72
73 private String workspace = null;
74
75 private String contentPath = null;
76
77 public void execute(JobExecutionContext context) throws JobExecutionException {
78 Session session = null;
79 try {
80
81 if (LOG.isInfoEnabled()) {
82 LOG.info("Start Execute ExportContentJob");
83 }
84 if (fromState == null) {
85
86 JobDataMap jdatamap = context.getJobDetail().getJobDataMap();
87
88 fromState = jdatamap.getString("fromState");
89 toState = jdatamap.getString("toState");
90 localTempDir = jdatamap.getString("localTempDir");
91 targetServerUrl = jdatamap.getString("targetServerUrl");
92 targetKey = jdatamap.getString("targetKey");
93 predefinedPath = jdatamap.getString("predefinedPath");
94 String[] pathTab = predefinedPath.split(":");
95 workspace = pathTab[1];
96 contentPath = pathTab[2];
97
98 if (LOG.isDebugEnabled()) {
99 LOG.debug("Init parameters first time :");
100 LOG.debug("\tFromState = " + fromState);
101 LOG.debug("\tToState = " + toState);
102 LOG.debug("\tLocalTempDir = " + localTempDir);
103 LOG.debug("\tTargetServerUrl = " + targetServerUrl);
104 }
105 }
106 SessionProvider sessionProvider = SessionProvider.createSystemProvider();
107
108 String containerName = WCMCoreUtils.getContainerNameFromJobContext(context);
109 RepositoryService repositoryService = WCMCoreUtils.getService(RepositoryService.class, containerName);
110 ManageableRepository manageableRepository = repositoryService.getCurrentRepository();
111 PublicationService publicationService = WCMCoreUtils.getService(PublicationService.class, containerName);
112 PublicationPlugin publicationPlugin = publicationService.getPublicationPlugins()
113 .get(AuthoringPublicationConstant.LIFECYCLE_NAME);
114 session = sessionProvider.getSession(workspace, manageableRepository);
115 QueryManager queryManager = session.getWorkspace().getQueryManager();
116 boolean isExported = false;
117 Query query = queryManager.createQuery("select * from nt:base where publication:currentState='"
118 + fromState
119 + "' and jcr:path like '"
120 + contentPath + "/%'",
121 Query.SQL);
122 File exportFolder = new File(localTempDir);
123 if (!exportFolder.exists())
124 exportFolder.mkdirs();
125 Date date = new Date();
126 long time = date.getTime();
127 File file = new File(localTempDir + File.separatorChar + time + ".xml");
128 ByteArrayOutputStream bos = null;
129 List<Node> categorySymLinks = null;
130 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
131 FileOutputStream output = new FileOutputStream(file);
132 XMLStreamWriter xmlsw = outputFactory.createXMLStreamWriter(output, "UTF-8");
133 xmlsw.writeStartDocument("UTF-8", "1.0");
134 xmlsw.writeStartElement("xs", "contents", URL);
135 xmlsw.writeNamespace("xs", URL);
136 QueryResult queryResult = query.execute();
137 if (queryResult.getNodes().getSize() > 0) {
138 TaxonomyService taxonomyService = WCMCoreUtils.getService(TaxonomyService.class, containerName);
139 Date nodeDate = null;
140 Date now = null;
141 xmlsw.writeStartElement("xs", "published-contents", URL);
142 for (NodeIterator iter = queryResult.getNodes(); iter.hasNext();) {
143 Node node = iter.nextNode();
144 nodeDate = null;
145 if (node.hasProperty(START_TIME_PROPERTY)) {
146 now = Calendar.getInstance().getTime();
147 nodeDate = node.getProperty(START_TIME_PROPERTY).getDate().getTime();
148 }
149
150 if (nodeDate == null || now.compareTo(nodeDate) >= 0) {
151 if (node.canAddMixin(MIX_TARGET_PATH))
152 node.addMixin(MIX_TARGET_PATH);
153 node.setProperty(MIX_TARGET_PATH, node.getPath());
154
155 if (node.canAddMixin(MIX_TARGET_WORKSPACE))
156 node.addMixin(MIX_TARGET_WORKSPACE);
157 node.setProperty(MIX_TARGET_WORKSPACE, workspace);
158 node.save();
159 HashMap<String, String> context_ = new HashMap<>();
160 context_.put("containerName", containerName);
161 publicationPlugin.changeState(node, toState, context_);
162 if (LOG.isInfoEnabled()) {
163 LOG.info("change the status of the node " + node.getPath() + " to " + toState);
164 }
165 bos = new ByteArrayOutputStream();
166
167 NodeLocation nodeLocation = NodeLocation.getNodeLocationByNode(node);
168 StringBuilder contenTargetPath = new StringBuilder();
169 contenTargetPath.append(nodeLocation.getRepository());
170 contenTargetPath.append(":");
171 contenTargetPath.append(nodeLocation.getWorkspace());
172 contenTargetPath.append(":");
173 contenTargetPath.append(nodeLocation.getPath());
174
175 session.exportSystemView(node.getPath(), bos, false, false);
176 if (!isExported)
177 isExported = true;
178 xmlsw.writeStartElement("xs", "published-content", URL);
179 xmlsw.writeAttribute("targetPath", contenTargetPath.toString());
180 xmlsw.writeStartElement("xs", "data", URL);
181 xmlsw.writeCData(bos.toString());
182 xmlsw.writeEndElement();
183 xmlsw.writeStartElement("xs", "links", URL);
184
185 categorySymLinks = taxonomyService.getAllCategories(node, true);
186
187 for (Node nodeSymlink : categorySymLinks) {
188
189 NodeLocation symlinkLocation = NodeLocation.getNodeLocationByNode(nodeSymlink);
190 StringBuilder symlinkTargetPath = new StringBuilder();
191 symlinkTargetPath.append(symlinkLocation.getRepository());
192 symlinkTargetPath.append(":");
193 symlinkTargetPath.append(symlinkLocation.getWorkspace());
194 symlinkTargetPath.append(":");
195 symlinkTargetPath.append(symlinkLocation.getPath());
196
197 xmlsw.writeStartElement("xs", "link", URL);
198 xmlsw.writeStartElement("xs", "type", URL);
199 xmlsw.writeCharacters("exo:taxonomyLink");
200 xmlsw.writeEndElement();
201 xmlsw.writeStartElement("xs", "title", URL);
202 xmlsw.writeCharacters(node.getName());
203 xmlsw.writeEndElement();
204 xmlsw.writeStartElement("xs", "targetPath", URL);
205 xmlsw.writeCharacters(symlinkTargetPath.toString());
206 xmlsw.writeEndElement();
207 xmlsw.writeEndElement();
208 }
209 xmlsw.writeEndElement();
210 xmlsw.writeEndElement();
211 }
212 }
213 xmlsw.writeEndElement();
214 }
215 query = queryManager.createQuery("select * from nt:base where publication:currentState='unpublished' and jcr:path like '"
216 + contentPath + "/%'",
217 Query.SQL);
218 queryResult = query.execute();
219 if (queryResult.getNodes().getSize() > 0) {
220 xmlsw.writeStartElement("xs", "unpublished-contents", URL);
221 for (NodeIterator iter = queryResult.getNodes(); iter.hasNext();) {
222 Node node = iter.nextNode();
223
224 if (node.isNodeType("nt:frozenNode"))
225 continue;
226 NodeLocation nodeLocation = NodeLocation.getNodeLocationByNode(node);
227 StringBuilder contenTargetPath = new StringBuilder();
228 contenTargetPath.append(nodeLocation.getRepository());
229 contenTargetPath.append(":");
230 contenTargetPath.append(nodeLocation.getWorkspace());
231 contenTargetPath.append(":");
232 contenTargetPath.append(nodeLocation.getPath());
233
234 xmlsw.writeStartElement("xs", "unpublished-content", URL);
235 xmlsw.writeAttribute("targetPath", contenTargetPath.toString());
236 xmlsw.writeEndElement();
237 if (!isExported)
238 isExported = true;
239 }
240 xmlsw.writeEndElement();
241 }
242 xmlsw.writeEndElement();
243 if (bos != null) {
244 bos.close();
245 }
246 xmlsw.flush();
247 output.close();
248 xmlsw.close();
249 if (!isExported)
250 file.delete();
251 File[] files = exportFolder.listFiles();
252 if (files != null) {
253 for (int i = 0; i < files.length; i++) {
254
255 URI uri = new URI(targetServerUrl + "/copyfile/copy/");
256 URL url = uri.toURL();
257 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
258
259
260 connection.setDoOutput(true);
261 connection.setDoInput(true);
262 connection.setRequestMethod("POST");
263 connection.setUseCaches(false);
264 connection.setRequestProperty("Content-type", "text/plain");
265 connection.setRequestProperty("Connection", "Keep-Alive");
266
267 OutputStream out = connection.getOutputStream();
268 BufferedReader reader = new BufferedReader(new FileReader(files[i].getPath()));
269 char[] buf = new char[1024];
270 int numRead = 0;
271 Date date_ = new Date();
272 Timestamp time_ = new Timestamp(date_.getTime());
273 String[] tab = targetKey.split("$TIMESTAMP");
274 StringBuilder resultKey = new StringBuilder();
275 for (int k = 0; k < tab.length; k++) {
276 resultKey.append(tab[k]);
277 if (k != (tab.length - 1))
278 resultKey.append(time_.toString());
279 }
280 String hashCode = SHAMessageDigester.getHash(resultKey.toString());
281 StringBuilder param = new StringBuilder();
282 param.append("timestamp=" + time_.toString() + "&&hashcode=" + hashCode
283 + "&&contentsfile=");
284 while ((numRead = reader.read(buf)) != -1) {
285 String readData = String.valueOf(buf, 0, numRead);
286 param.append(readData);
287 }
288 reader.close();
289 out.write(param.toString().getBytes());
290 out.flush();
291 connection.connect();
292 BufferedReader inStream = new BufferedReader(new InputStreamReader(connection.getInputStream()));
293 out.close();
294 String string = null;
295 while ((string = inStream.readLine()) != null) {
296 if (LOG.isDebugEnabled()) {
297 LOG.debug("The response of the production server:" + string);
298 }
299 }
300 connection.disconnect();
301 files[i].delete();
302 }
303 }
304
305 if (LOG.isInfoEnabled()) {
306 LOG.info("End Execute ExportContentJob");
307 }
308 } catch (RepositoryException ex) {
309 if (LOG.isErrorEnabled()) {
310 LOG.error("Repository 'repository ' not found.", ex);
311 }
312 } catch (ConnectException ex) {
313 if (LOG.isErrorEnabled()) {
314 LOG.error("The front server is down.", ex);
315 }
316 } catch (Exception ex) {
317 if (LOG.isErrorEnabled()) {
318 LOG.error("Error when exporting content : ", ex);
319 }
320 } finally {
321 if (session != null)
322 session.logout();
323 }
324 }
325 }