View Javadoc

1   package com.atlassian.scheduler.core.util;
2   
3   import com.atlassian.scheduler.SchedulerServiceException;
4   import com.atlassian.scheduler.config.JobId;
5   import com.atlassian.scheduler.config.RunMode;
6   import com.atlassian.scheduler.core.status.AbstractJobDetailsFactory;
7   import com.google.common.collect.ImmutableMap;
8   
9   import javax.annotation.Nonnull;
10  import javax.annotation.Nullable;
11  import java.io.ByteArrayOutputStream;
12  import java.io.IOException;
13  import java.io.ObjectInputStream;
14  import java.io.ObjectOutputStream;
15  import java.io.Serializable;
16  import java.util.Map;
17  
18  /**
19   * Utility for serializing the parameters map to a {@code byte[]} and restoring it to its
20   * original form.
21   *
22   * @since v1.0
23   */
24  public class ParameterMapSerializer {
25      /**
26       * Serializes the parameters to a byte array.  It is highly recommended that {@code SchedulerService}
27       * implementations use this serialization to make it possible to
28       * {@link AbstractJobDetailsFactory#buildJobDetails(JobId, Object, RunMode)} reconstruct}
29       * the {@code JobDetails} even when the {@code JobRunner} for it has not been registered.
30       * Otherwise, it will be difficult to recover any information about the job at all.
31       *
32       * @param parameters the parameters map to serialize; may be {@code null} as shorthand for an empty map
33       * @return the serialized parameters map, or {@code null} if {@code parameters} was either {@code null} or empty
34       * @throws SchedulerServiceException if the parameters map cannot be serialized, presumably
35       *                                   because it contains an object that cannot be serialized
36       */
37      @Nullable
38      public byte[] serializeParameters(@Nullable Map<String, Serializable> parameters)
39              throws SchedulerServiceException {
40          if (parameters == null || parameters.isEmpty()) {
41              return null;
42          }
43          final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
44          try {
45              final ObjectOutputStream out = new ObjectOutputStream(bytes);
46              try {
47                  out.writeObject(parameters);
48              } finally {
49                  out.close();
50              }
51          } catch (IOException ioe) {
52              throw new SchedulerServiceException("Serialization failed", ioe);
53          }
54          return bytes.toByteArray();
55      }
56  
57      /**
58       * Deserializes the parameters map from a byte array using the provided {@code ClassLoader}.
59       *
60       * @param classLoader the class loader to use for resolving classes
61       * @param parameters  the parameters to be deserialized; may be {@code null}, which results in an
62       *                    empty map
63       * @return the deserialized parameters
64       * @throws ClassNotFoundException if {@link ClassLoaderAwareObjectInputStream} does
65       * @throws IOException            if {@link ClassLoaderAwareObjectInputStream} does
66       */
67      @Nonnull
68      public Map<String, Serializable> deserializeParameters(final ClassLoader classLoader,
69                                                             @Nullable final byte[] parameters) throws ClassNotFoundException, IOException {
70          if (parameters == null) {
71              return ImmutableMap.of();
72          }
73          final ObjectInputStream in = createObjectInputStream(classLoader, parameters);
74          try {
75              return readParameterMap(in);
76          } finally {
77              in.close();
78          }
79      }
80  
81      protected ObjectInputStream createObjectInputStream(final ClassLoader classLoader, final byte[] parameters)
82              throws IOException {
83          return new ClassLoaderAwareObjectInputStream(classLoader, parameters);
84      }
85  
86      private Map<String, Serializable> readParameterMap(final ObjectInputStream in)
87              throws IOException, ClassNotFoundException {
88          @SuppressWarnings("unchecked")
89          final Map<String, Serializable> map = (Map<String, Serializable>) in.readObject();
90          if (map != null) {
91              return map;
92          }
93          return ImmutableMap.of();
94      }
95  
96  }