/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sun.jini.mercury; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.SyncFailedException; import java.rmi.MarshalledObject; import net.jini.core.event.RemoteEvent; /** * This class provides the interface for writing <tt>RemoteEvent</tt>s to * a given <tt>LogOutputStream</tt>. * * @author Sun Microsystems, Inc. * * @since 1.1 */ class EventWriter { /** * This class extends <tt>ObjectOutputStream</tt> in order to obtain * object writing methods. This class is used in conjunction with * <tt>SwitchOutputStream</tt> in order to provide a re-targetable * output stream capability. */ private static class EventOutputStream extends ObjectOutputStream { /** * Simple constructor that passes its argument to the superclass * * @exception IOException if an I/O error occurs */ public EventOutputStream(OutputStream out) throws IOException { super(out); } /** * Overrides <tt>ObjectOutputStream</tt>'s method with no-op * functionality. This prevents the underlying stream from being * being accessed during construction. See <tt>SwitchOutputStream</tt>. * * @exception IOException if an I/O error occurs */ protected void writeStreamHeader() throws IOException { // Do nothing } } /** * This class is intended to be the <tt>OutputStream</tt> provided * to <tt>EventOutputStream</tt>'s constructor. This class essentially * delegates <tt>OutputStream</tt> functionality to the provided * <tt>LogOutputStream</tt>. The <tt>setOutputStream</tt> method * allows the underlying <tt>LogOutputStream</tt> to be re-targeted * at runtime. */ private static class SwitchOutputStream extends OutputStream { /** The delegation target for the <tt>OutputStream</tt> methods */ private LogOutputStream out; /** * Simple constructor that assigns the given argument to the * appropriate internal field. */ public SwitchOutputStream(LogOutputStream out) { this.out = out; } // documentation inherited from supertype public void write(int b) throws IOException { out.write(b); } // documentation inherited from supertype public void write(byte[] b) throws IOException { out.write(b); } // documentation inherited from supertype public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); } // documentation inherited from supertype public void flush() throws IOException { out.flush(); } // documentation inherited from supertype public void close() throws IOException { out.close(); } /** Sets the delegation target */ public void setOutputStream(LogOutputStream out) { this.out = out; } } /** Reference to <tt>EventOutputStream</tt> for this class */ private EventOutputStream eout; /** Reference to <tt>SwitchOutputStream</tt> for this class */ private SwitchOutputStream sout; /** * Simple constructor that creates the appropriate internal objects. * * @exception IOException if an I/O error occurs */ public EventWriter() throws IOException { // default delegation target is null sout = new SwitchOutputStream(null); // Use the "switchable" output stream as the target eout = new EventOutputStream(sout); } /** * Writes the given <tt>RemoteEvent</tt> to the provided * <tt>LogOutputStream</tt>. It also attempts to synchronize * the write with the underlying storage mechanism. * * @exception IOException * Thrown if an I/O error occurs * @exception SyncFailedException * Thrown when the buffers cannot be flushed, * or because the system cannot guarantee that all the * buffers have been synchronized with physical media. */ public void write(RemoteEvent ev, LogOutputStream out) throws IOException, SyncFailedException { // Set stream target sout.setOutputStream(out); try { // Wrap the event as a MarshalledObject so that // we can ensure a successful read later on (i.e. // should always be able to read MarshalledObject // but we might not be able to reconstruct a // RemoteEvent object because of codebase problems). MarshalledObject mo = new MarshalledObject(ev); eout.reset(); eout.writeObject(mo); eout.flush(); out.sync(); } finally { // reset target to null sout.setOutputStream(null); } } }