1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package com.sun.jini.logging;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26 import java.io.ObjectStreamClass;
27 import java.io.ObjectStreamException;
28 import java.io.OutputStream;
29 import java.io.Serializable;
30 import java.util.logging.Level;
31 import org.apache.river.api.io.AtomicSerial;
32 import org.apache.river.api.io.AtomicSerial.GetArg;
33
34 /**
35 * Defines additional {@link Level} values.
36 *
37 * @since 2.0
38 */
39 @Deprecated
40 public class Levels {
41
42 /**
43 * <p>
44 * <code>FAILED</code> is a message level indicating that a facility has
45 * experienced a failure that it will reflect to its caller. </p>
46 * <p>
47 * <code>FAILED</code> messages are intended to provide users with
48 * information about failures produced by internal components in order to
49 * assist with debugging problems in systems with multiple components. This
50 * level is initialized to <code>600</code>.</p>
51 */
52 public static final Level FAILED = createLevel("FAILED", 600, null);
53
54 /**
55 * <p>
56 * <code>HANDLED</code> is a message level indicating that a facility has
57 * detected a failure that it will take steps to handle without reflecting
58 * the failure to its caller. </p>
59 * <p>
60 * <code>HANDLED</code> messages are intended to provide users with
61 * information about failures detected by internal components in order to
62 * assist with debugging problems in systems with multiple components. This
63 * level is initialized to <code>550</code>.</p>
64 */
65 public static final Level HANDLED = createLevel("HANDLED", 550, null);
66
67 /**
68 * This class cannot be instantiated.
69 */
70 private Levels() {
71 throw new AssertionError("This class cannot be instantiated");
72 }
73
74 /**
75 * Defines a class that has the same data format as the Level class, to
76 * permit creating the serialized form of a Level instance.
77 */
78 @AtomicSerial
79 private static final class LevelData implements Serializable {
80 private static final long serialVersionUID = -8176160795706313070L;
81 private final String name;
82 private final int value;
83 private final String resourceBundleName;
84 private final String localizedLevelName;
85
86 LevelData(String name, int value, String resourceBundleName) {
87 this.name = name;
88 this.value = value;
89 this.resourceBundleName = resourceBundleName;
90 this.localizedLevelName = resourceBundleName == null ? name : null;
91 }
92
93 private LevelData(String name,
94 int value,
95 String resourceBundleName,
96 String localizedLevelName)
97 {
98 this.name = name;
99 this.value = value;
100 this.resourceBundleName = resourceBundleName;
101 this.localizedLevelName = localizedLevelName;
102 }
103
104 public LevelData(GetArg arg) throws IOException{
105 this(arg.get("name", null, String.class),
106 arg.get("value", 0),
107 arg.get("resourceBundleName", null, String.class),
108 arg.get("localizedLevelName", null, String.class)
109 );
110 }
111 }
112
113 /**
114 * Defines an object output stream that allows the data for one class to be
115 * interpreted as the data for another class. This class is useful in
116 * creating serialization data for a class when access to an appropriate
117 * constructor is not available.
118 */
119 private static final class ClassReplacingObjectOutputStream extends ObjectOutputStream {
120 private final ObjectStreamClass from;
121 private final ObjectStreamClass to;
122 ClassReplacingObjectOutputStream(OutputStream out, Class from, Class to) throws IOException {
123 super(out);
124 this.from = ObjectStreamClass.lookup(from);
125 this.to = ObjectStreamClass.lookup(to);
126 }
127
128 protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
129 if (from.equals(desc)) {
130 desc = to;
131 }
132 super.writeClassDescriptor(desc);
133 }
134 }
135
136 /**
137 * Creates an instance of the Level class. This method works around the
138 * fact that there is no public constructor for the Level class by
139 * constructing the serialized form for an instance with the specified
140 * field values and deserializing it.
141 *
142 * If deserialization fails, it creates a Level with a numerical name that
143 * can be de-serialised by a remote client that doesn't have
144 * org.apache.river.logging.Levels bytecode.
145 *
146 * Local logging code still enjoys the benefit of a meaningful name even
147 * when deserialization fails.
148 *
149 * See River-416 for details, the serial form of Levels was broken in Java 1.6.0_41.
150 */
151 private static Level createLevel(String name, int value, String resourceBundleName) {
152 Level result = null;
153 try {
154 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
155 ObjectOutputStream out = new ClassReplacingObjectOutputStream(bytes, LevelData.class, Level.class);
156 out.writeObject(new LevelData(name, value, resourceBundleName));
157 out.close();
158 ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()));
159 result = (Level) in.readObject();
160 in.close();
161 // If this suceeds, Level.readResolve has added the new Level to its internal List.
162
163 } catch (ClassNotFoundException ex) {
164 // Ignore :)
165 } catch (IOException e) {
166 // Ignore :)
167 } finally {
168 if (result == null){
169 final Level withoutName = Level.parse(Integer.valueOf(value).toString());
170 result = new Level(name, value, resourceBundleName) {
171 Object writeReplace() throws ObjectStreamException {
172 return withoutName;
173 }
174 };
175 }
176 return result;
177 }
178 }
179 }