001: /*
002:
003: Derby - Class org.apache.derby.impl.services.stream.SingleStream
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.services.stream;
023:
024: import org.apache.derby.iapi.services.stream.InfoStreams;
025: import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
026: import org.apache.derby.iapi.services.stream.PrintWriterGetHeader;
027:
028: import org.apache.derby.iapi.services.sanity.SanityManager;
029: import org.apache.derby.iapi.services.monitor.ModuleControl;
030: import org.apache.derby.iapi.services.monitor.ModuleSupportable;
031: import org.apache.derby.iapi.services.monitor.Monitor;
032:
033: import org.apache.derby.iapi.reference.Property;
034: import org.apache.derby.iapi.services.property.PropertyUtil;
035:
036: import java.io.BufferedOutputStream;
037: import java.io.FileOutputStream;
038: import java.io.IOException;
039: import java.io.OutputStream;
040: import java.io.File;
041: import java.io.Writer;
042:
043: import java.util.Properties;
044:
045: import java.lang.reflect.Method;
046: import java.lang.reflect.Field;
047: import java.lang.reflect.Modifier;
048: import java.lang.reflect.Member;
049: import java.lang.reflect.InvocationTargetException;
050:
051: /**
052: *
053: * The Basic Services provide InfoStreams for reporting
054: * information. Two streams are provided: trace and error.
055: * It is configurable where these streams are directed.
056: * <p>
057: * Errors will be printed to the error stream in addition
058: * to being sent to the client.
059: * <p>
060: * By default both streams are sent to an error log
061: * for the system. When creating a message for a stream,
062: * you can create an initial entry with header information
063: * and then append to it as many times as desired.
064: * <p>
065: * Note: if character encodings are needed, the use of
066: * java.io.*OutputStream's should be replaced with
067: * java.io.*Writer's (assuming the Writer interface
068: * remains stable in JDK1.1)
069: *
070: * @author ames
071: */
072: public final class SingleStream implements InfoStreams, ModuleControl,
073: java.security.PrivilegedAction {
074:
075: /*
076: ** Instance fields
077: */
078: private HeaderPrintWriter theStream;
079:
080: /**
081: The no-arg public constructor for ModuleControl's use.
082: */
083: public SingleStream() {
084: }
085:
086: /**
087: * @see org.apache.derby.iapi.services.monitor.ModuleControl#boot
088: */
089: public void boot(boolean create, Properties properties) {
090: theStream = makeStream();
091: }
092:
093: /**
094: * @see org.apache.derby.iapi.services.monitor.ModuleControl#stop
095: */
096: public void stop() {
097: ((BasicHeaderPrintWriter) theStream).complete();
098: }
099:
100: /*
101: * InfoStreams interface
102: */
103:
104: /**
105: * @see org.apache.derby.iapi.services.stream.InfoStreams#stream
106: */
107: public HeaderPrintWriter stream() {
108: return theStream;
109: }
110:
111: //
112: // class interface
113: //
114:
115: /**
116: Make the stream; note that service properties override
117: application and system properties.
118:
119: */
120: private HeaderPrintWriter makeStream() {
121:
122: // get the header
123: PrintWriterGetHeader header = makeHeader();
124: HeaderPrintWriter hpw = makeHPW(header);
125:
126: // If hpw == null then no properties were specified for the stream
127: // so use/create the default stream.
128: if (hpw == null)
129: hpw = createDefaultStream(header);
130: return hpw;
131: }
132:
133: /**
134: Return a new header object.
135: */
136: private PrintWriterGetHeader makeHeader() {
137:
138: return new BasicGetLogHeader(true, true, (String) null);
139: }
140:
141: /**
142: create a HeaderPrintWriter based on the header.
143: Will still need to determine the target type.
144: */
145: private HeaderPrintWriter makeHPW(PrintWriterGetHeader header) {
146:
147: // the type of target is based on which property is used
148: // to set it. choices are file, method, field, stream
149:
150: String target = PropertyUtil
151: .getSystemProperty(Property.ERRORLOG_FILE_PROPERTY);
152: if (target != null)
153: return makeFileHPW(target, header);
154:
155: target = PropertyUtil
156: .getSystemProperty(Property.ERRORLOG_METHOD_PROPERTY);
157: if (target != null)
158: return makeMethodHPW(target, header);
159:
160: target = PropertyUtil
161: .getSystemProperty(Property.ERRORLOG_FIELD_PROPERTY);
162: if (target != null)
163: return makeFieldHPW(target, header);
164:
165: return null;
166: }
167:
168: /**
169: Make a header print writer out of a file name. If it is a relative
170: path name then it is taken as relative to derby.system.home if that is set,
171: otherwise relative to the current directory. If the path name is absolute
172: then it is taken as absolute.
173: */
174: private HeaderPrintWriter PBmakeFileHPW(String fileName,
175: PrintWriterGetHeader header) {
176:
177: boolean appendInfoLog = PropertyUtil
178: .getSystemBoolean(Property.LOG_FILE_APPEND);
179:
180: File streamFile = new File(fileName);
181:
182: // See if this needs to be made relative to something ...
183: if (!streamFile.isAbsolute()) {
184: Object monitorEnv = Monitor.getMonitor().getEnvironment();
185: if (monitorEnv instanceof File)
186: streamFile = new File((File) monitorEnv, fileName);
187: }
188:
189: FileOutputStream fos;
190:
191: try {
192:
193: if (streamFile.exists() && appendInfoLog)
194: fos = new FileOutputStream(streamFile.getPath(), true);
195: else
196: fos = new FileOutputStream(streamFile);
197: } catch (IOException ioe) {
198: return useDefaultStream(header, ioe);
199: } catch (SecurityException se) {
200: return useDefaultStream(header, se);
201: }
202:
203: return new BasicHeaderPrintWriter(
204: new BufferedOutputStream(fos), header, true, streamFile
205: .getPath());
206: }
207:
208: private HeaderPrintWriter makeMethodHPW(String methodInvocation,
209: PrintWriterGetHeader header) {
210:
211: int lastDot = methodInvocation.lastIndexOf('.');
212: String className = methodInvocation.substring(0, lastDot);
213: String methodName = methodInvocation.substring(lastDot + 1);
214:
215: Throwable t;
216: try {
217: Class theClass = Class.forName(className);
218:
219: try {
220: Method theMethod = theClass.getMethod(methodName,
221: new Class[0]);
222:
223: if (!Modifier.isStatic(theMethod.getModifiers())) {
224: HeaderPrintWriter hpw = useDefaultStream(header);
225: hpw.printlnWithHeader(theMethod.toString()
226: + " is not static");
227: return hpw;
228: }
229:
230: try {
231: return makeValueHPW(theMethod, theMethod.invoke(
232: (Object) null, new Object[0]), header,
233: methodInvocation);
234: } catch (IllegalAccessException iae) {
235: t = iae;
236: } catch (IllegalArgumentException iarge) {
237: t = iarge;
238: } catch (InvocationTargetException ite) {
239: t = ite.getTargetException();
240: }
241:
242: } catch (NoSuchMethodException nsme) {
243: t = nsme;
244: }
245: } catch (ClassNotFoundException cnfe) {
246: t = cnfe;
247: } catch (SecurityException se) {
248: t = se;
249:
250: }
251: return useDefaultStream(header, t);
252:
253: }
254:
255: private HeaderPrintWriter makeFieldHPW(String fieldAccess,
256: PrintWriterGetHeader header) {
257:
258: int lastDot = fieldAccess.lastIndexOf('.');
259: String className = fieldAccess.substring(0, lastDot);
260: String fieldName = fieldAccess.substring(lastDot + 1,
261: fieldAccess.length());
262:
263: Throwable t;
264: try {
265: Class theClass = Class.forName(className);
266:
267: try {
268: Field theField = theClass.getField(fieldName);
269:
270: if (!Modifier.isStatic(theField.getModifiers())) {
271: HeaderPrintWriter hpw = useDefaultStream(header);
272: hpw.printlnWithHeader(theField.toString()
273: + " is not static");
274: return hpw;
275: }
276:
277: try {
278: return makeValueHPW(theField, theField
279: .get((Object) null), header, fieldAccess);
280: } catch (IllegalAccessException iae) {
281: t = iae;
282: } catch (IllegalArgumentException iarge) {
283: t = iarge;
284: }
285:
286: } catch (NoSuchFieldException nsfe) {
287: t = nsfe;
288: }
289: } catch (ClassNotFoundException cnfe) {
290: t = cnfe;
291: } catch (SecurityException se) {
292: t = se;
293: }
294: return useDefaultStream(header, t);
295:
296: /*
297: If we decide it is a bad idea to use reflect and need
298: an alternate implementation, we can hard-wire those
299: fields that we desire to give configurations access to,
300: like so:
301:
302: if ("java.lang.System.out".equals(fieldAccess))
303: os = System.out;
304: else if ("java.lang.System.err".equals(fieldAccess))
305: os = System.err;
306: */
307: }
308:
309: private HeaderPrintWriter makeValueHPW(Member whereFrom,
310: Object value, PrintWriterGetHeader header, String name) {
311:
312: if (value instanceof OutputStream)
313: return new BasicHeaderPrintWriter((OutputStream) value,
314: header, false, name);
315: else if (value instanceof Writer)
316: return new BasicHeaderPrintWriter((Writer) value, header,
317: false, name);
318:
319: HeaderPrintWriter hpw = useDefaultStream(header);
320:
321: if (value == null)
322: hpw.printlnWithHeader(whereFrom.toString() + "=null");
323: else
324: hpw.printlnWithHeader(whereFrom.toString() + " instanceof "
325: + value.getClass().getName());
326:
327: return hpw;
328: }
329:
330: /**
331: Used when no configuration information exists for a stream.
332: */
333: private HeaderPrintWriter createDefaultStream(
334: PrintWriterGetHeader header) {
335: return makeFileHPW("derby.log", header);
336: }
337:
338: /**
339: Used when creating a stream creates an error.
340: */
341: private HeaderPrintWriter useDefaultStream(
342: PrintWriterGetHeader header) {
343:
344: return new BasicHeaderPrintWriter(System.err, header, false,
345: "System.err");
346: }
347:
348: private HeaderPrintWriter useDefaultStream(
349: PrintWriterGetHeader header, Throwable t) {
350:
351: HeaderPrintWriter hpw = useDefaultStream(header);
352: hpw.printlnWithHeader(t.toString());
353: return hpw;
354: }
355:
356: /*
357: ** Priv block code, moved out of the old Java2 version.
358: */
359:
360: private String PBfileName;
361: private PrintWriterGetHeader PBheader;
362:
363: private HeaderPrintWriter makeFileHPW(String fileName,
364: PrintWriterGetHeader header) {
365: this .PBfileName = fileName;
366: this .PBheader = header;
367: return (HeaderPrintWriter) java.security.AccessController
368: .doPrivileged(this );
369: }
370:
371: public final Object run() {
372: // SECURITY PERMISSION - OP4, OP5
373: return PBmakeFileHPW(PBfileName, PBheader);
374: }
375: }
|