001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.service.impl;
016    
017    import com.liferay.portal.kernel.dao.db.DB;
018    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
019    import com.liferay.portal.kernel.dao.jdbc.DataAccess;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
022    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
023    import com.liferay.portal.kernel.json.JSONFactoryUtil;
024    import com.liferay.portal.kernel.json.JSONObject;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.messaging.Message;
028    import com.liferay.portal.kernel.scheduler.SchedulerEngine;
029    import com.liferay.portal.messaging.LayoutsLocalPublisherRequest;
030    import com.liferay.portal.messaging.LayoutsRemotePublisherRequest;
031    import com.liferay.portal.service.base.QuartzLocalServiceBaseImpl;
032    
033    import java.io.ByteArrayInputStream;
034    import java.io.ByteArrayOutputStream;
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.io.ObjectInputStream;
038    import java.io.ObjectOutputStream;
039    import java.io.ObjectStreamClass;
040    
041    import java.sql.Connection;
042    import java.sql.PreparedStatement;
043    import java.sql.ResultSet;
044    
045    import java.util.ArrayList;
046    import java.util.HashMap;
047    import java.util.List;
048    import java.util.Map;
049    import java.util.Properties;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     * @author Shuyang Zhou
054     */
055    public class QuartzLocalServiceImpl extends QuartzLocalServiceBaseImpl {
056    
057            public void checkQuartzTables() throws SystemException {
058                    createQuartzTables();
059                    updateQuartzJobDetails();
060                    updateQuartzTriggers();
061            }
062    
063            protected byte[] convertMessageToJSON(byte[] jobData)
064                    throws Exception {
065    
066                    ObjectInputStream objectInputStream =
067                            new BackwardCompatibleObjectInputStream(
068                                    new UnsyncByteArrayInputStream(jobData));
069    
070                    Map<Object, Object> jobDataMap =
071                            (Map<Object, Object>)objectInputStream.readObject();
072    
073                    objectInputStream.close();
074    
075                    Map<Object, Object> tempJobDataMap = new HashMap<Object, Object>(
076                            jobDataMap);
077    
078                    jobDataMap.clear();
079    
080                    boolean modifiedKeys = false;
081    
082                    for (Map.Entry<Object, Object> entry : tempJobDataMap.entrySet()) {
083                            Object key = entry.getKey();
084    
085                            if (key instanceof String) {
086                                    String stringKey = (String)key;
087    
088                                    if (stringKey.startsWith("destination")) {
089                                            key = SchedulerEngine.DESTINATION_NAME;
090                                    }
091                                    else if (stringKey.equals("messageBody")) {
092                                            key = SchedulerEngine.MESSAGE;
093    
094                                            jobDataMap.put(
095                                                    key, convertOldJsonStringToObject(entry.getValue()));
096    
097                                            continue;
098                                    }
099                                    else {
100                                            key = stringKey.toUpperCase();
101                                    }
102    
103                                    modifiedKeys = true;
104                            }
105    
106                            jobDataMap.put(key, entry.getValue());
107                    }
108    
109                    Object object = jobDataMap.get(SchedulerEngine.MESSAGE);
110    
111                    if ((object == null) || (object instanceof String) || !modifiedKeys) {
112                            return null;
113                    }
114    
115                    Message message = null;
116    
117                    if (object instanceof Message) {
118                            message = (Message)object;
119                    }
120                    else {
121                            message = new Message();
122    
123                            message.setPayload(object);
124                    }
125    
126                    String messageJSON = JSONFactoryUtil.serialize(message);
127    
128                    jobDataMap.put(SchedulerEngine.MESSAGE, messageJSON);
129    
130                    UnsyncByteArrayOutputStream newJobDataOutputStream =
131                            new UnsyncByteArrayOutputStream();
132                    ObjectOutputStream objectOutputStream = new ObjectOutputStream(
133                            newJobDataOutputStream);
134    
135                    objectOutputStream.writeObject(jobDataMap);
136    
137                    objectOutputStream.close();
138    
139                    return newJobDataOutputStream.toByteArray();
140            }
141    
142            @SuppressWarnings("deprecation")
143            protected Object convertOldJsonStringToObject(Object object) {
144                    if (!(object instanceof String)) {
145                            return null;
146                    }
147    
148                    String jsonString = (String)object;
149    
150                    JSONObject jsonObject = null;
151    
152                    try {
153                            jsonObject = JSONFactoryUtil.createJSONObject(jsonString);
154                    }
155                    catch (Exception e) {
156                            if (_log.isWarnEnabled()) {
157                                    _log.warn(e, e);
158                            }
159                    }
160    
161                    String oldJavaClass = jsonObject.getString("javaClass");
162    
163                    if (oldJavaClass.equals(
164                                    com.liferay.portlet.communities.messaging.
165                                            LayoutsLocalPublisherRequest.class.getName())) {
166    
167                            jsonObject.put(
168                                    "javaClass", LayoutsLocalPublisherRequest.class.getName());
169                    }
170                    else if (oldJavaClass.equals(
171                                            com.liferay.portlet.communities.messaging.
172                                                    LayoutsRemotePublisherRequest.class.getName())) {
173    
174                            jsonObject.put(
175                                    "javaClass", LayoutsRemotePublisherRequest.class.getName());
176                    }
177    
178                    jsonString = jsonObject.toString();
179    
180                    return JSONFactoryUtil.deserialize(jsonString);
181            }
182    
183            protected byte[] convertPropertiesToMap(byte[] jobData) throws Exception {
184                    InputStream inputStream = null;
185    
186                    try {
187                            inputStream = new ByteArrayInputStream(jobData);
188    
189                            new ObjectInputStream(inputStream);
190    
191                            return jobData;
192                    }
193                    catch (Exception e) {
194                            Properties properties = new Properties();
195    
196                            properties.load(inputStream);
197    
198                            ByteArrayOutputStream byteArrayOutputStream =
199                                    new ByteArrayOutputStream();
200    
201                            ObjectOutputStream objectOutputStream = new ObjectOutputStream(
202                                    byteArrayOutputStream);
203    
204                            objectOutputStream.writeObject(
205                                    new HashMap<Object, Object>(properties));
206    
207                            objectOutputStream.flush();
208    
209                            return byteArrayOutputStream.toByteArray();
210                    }
211                    finally {
212                            inputStream.close();
213                    }
214            }
215    
216            protected void createQuartzTables() throws SystemException {
217                    Connection con = null;
218                    PreparedStatement ps = null;
219                    ResultSet rs = null;
220    
221                    try {
222                            con = DataAccess.getConnection();
223    
224                            ps = con.prepareStatement(
225                                    "select count(*) from QUARTZ_JOB_DETAILS");
226    
227                            rs = ps.executeQuery();
228    
229                            if (rs.next()) {
230                                    return;
231                            }
232                    }
233                    catch (Exception e) {
234                            if (_log.isWarnEnabled()) {
235                                    _log.warn(e, e);
236                            }
237                    }
238                    finally {
239                            DataAccess.cleanUp(con, ps, rs);
240                    }
241    
242                    DB db = DBFactoryUtil.getDB();
243    
244                    try {
245                            db.runSQLTemplate("quartz-tables.sql", false);
246                    }
247                    catch (Exception e) {
248                            throw new SystemException(e);
249                    }
250            }
251    
252            protected void updateQuartzJobDetails() {
253                    Connection con = null;
254                    PreparedStatement ps = null;
255                    ResultSet rs = null;
256    
257                    List<Object[]> arrays = new ArrayList<Object[]>();
258    
259                    try {
260                            con = DataAccess.getConnection();
261    
262                            ps = con.prepareStatement(
263                                    "select JOB_NAME, JOB_GROUP, JOB_DATA from QUARTZ_JOB_DETAILS");
264    
265                            rs = ps.executeQuery();
266    
267                            while (rs.next()) {
268                                    String jobName = rs.getString("JOB_NAME");
269                                    String jobGroup = rs.getString("JOB_GROUP");
270                                    byte[] jobData = rs.getBytes("JOB_DATA");
271    
272                                    jobData = convertPropertiesToMap(jobData);
273                                    jobData = convertMessageToJSON(jobData);
274    
275                                    if (jobData == null) {
276                                            continue;
277                                    }
278    
279                                    Object[] array = new Object[3];
280    
281                                    array[0] = jobName;
282                                    array[1] = jobGroup;
283                                    array[2] = jobData;
284    
285                                    arrays.add(array);
286                            }
287                    }
288                    catch (Exception e) {
289                            _log.error(e, e);
290                    }
291                    finally {
292                            DataAccess.cleanUp(con, ps, rs);
293                    }
294    
295                    if (arrays.isEmpty()) {
296                            return;
297                    }
298    
299                    try {
300                            con = DataAccess.getConnection();
301    
302                            ps = con.prepareStatement(
303                                    "update QUARTZ_JOB_DETAILS set JOB_DATA = ? where JOB_NAME = " +
304                                            "? and JOB_GROUP = ?");
305    
306                            for (Object[] array : arrays) {
307                                    String jobName = (String)array[0];
308                                    String jobGroup = (String)array[1];
309                                    byte[] jobData = (byte[])array[2];
310    
311                                    ps.setBytes(1, jobData);
312                                    ps.setString(2, jobName);
313                                    ps.setString(3, jobGroup);
314    
315                                    ps.executeUpdate();
316                            }
317                    }
318                    catch (Exception e) {
319                            _log.error(e, e);
320                    }
321                    finally {
322                            DataAccess.cleanUp(con, ps, rs);
323                    }
324            }
325    
326            protected void updateQuartzTriggers() {
327                    DB db = DBFactoryUtil.getDB();
328    
329                    String dbType = db.getType();
330    
331                    if (!dbType.equals(DB.TYPE_SYBASE)) {
332                            return;
333                    }
334    
335                    Connection con = null;
336                    PreparedStatement ps = null;
337                    ResultSet rs = null;
338    
339                    List<Object[]> arrays = new ArrayList<Object[]>();
340    
341                    try {
342                            con = DataAccess.getConnection();
343    
344                            ps = con.prepareStatement(
345                                    "select JOB_NAME, JOB_GROUP, JOB_DATA from QUARTZ_TRIGGERS");
346    
347                            rs = ps.executeQuery();
348    
349                            while (rs.next()) {
350                                    String jobName = rs.getString("JOB_NAME");
351                                    String jobGroup = rs.getString("JOB_GROUP");
352                                    byte[] jobData = rs.getBytes("JOB_DATA");
353    
354                                    if ((jobData == null) || (jobData.length != 1)) {
355                                            continue;
356                                    }
357    
358                                    if (jobData[0] != 0) {
359                                            continue;
360                                    }
361    
362                                    Object[] array = new Object[2];
363    
364                                    array[0] = jobName;
365                                    array[1] = jobGroup;
366    
367                                    arrays.add(array);
368                            }
369                    }
370                    catch (Exception e) {
371                            _log.error(e, e);
372                    }
373                    finally {
374                            DataAccess.cleanUp(con, ps, rs);
375                    }
376    
377                    if (arrays.isEmpty()) {
378                            return;
379                    }
380    
381                    try {
382                            con = DataAccess.getConnection();
383    
384                            ps = con.prepareStatement(
385                                    "update QUARTZ_TRIGGERS set JOB_DATA = ? where JOB_NAME = ? " +
386                                            "and JOB_GROUP = ?");
387    
388                            for (Object[] array : arrays) {
389                                    String jobName = (String)array[0];
390                                    String jobGroup = (String)array[1];
391    
392                                    ps.setBytes(1, null);
393                                    ps.setString(2, jobName);
394                                    ps.setString(3, jobGroup);
395    
396                                    ps.executeUpdate();
397                            }
398                    }
399                    catch (Exception e) {
400                            _log.error(e, e);
401                    }
402                    finally {
403                            DataAccess.cleanUp(con, ps, rs);
404                    }
405            }
406    
407            private static Log _log = LogFactoryUtil.getLog(
408                    QuartzLocalServiceImpl.class);
409    
410            private class BackwardCompatibleObjectInputStream
411                    extends ObjectInputStream {
412    
413                    public BackwardCompatibleObjectInputStream(InputStream inputStream)
414                            throws IOException {
415    
416                            super(inputStream);
417                    }
418    
419                    @Override
420                    @SuppressWarnings("deprecation")
421                    protected ObjectStreamClass readClassDescriptor()
422                            throws ClassNotFoundException, IOException {
423    
424                            ObjectStreamClass objectStreamClass = super.readClassDescriptor();
425    
426                            String name = objectStreamClass.getName();
427    
428                            if (name.equals(Message.class.getName())) {
429                                    return ObjectStreamClass.lookup(Message.class);
430                            }
431                            else if (name.equals(
432                                                    com.liferay.portlet.communities.messaging.
433                                                            LayoutsLocalPublisherRequest.class.getName())) {
434    
435                                    return ObjectStreamClass.lookup(
436                                            LayoutsLocalPublisherRequest.class);
437                            }
438                            else if (name.equals(
439                                                    com.liferay.portlet.communities.messaging.
440                                                            LayoutsRemotePublisherRequest.class.getName())) {
441    
442                                    return ObjectStreamClass.lookup(
443                                            LayoutsRemotePublisherRequest.class);
444                            }
445                            else {
446                                    return objectStreamClass;
447                            }
448                    }
449    
450            }
451    
452    }