001    /*
002     *   Licensed to the Apache Software Foundation (ASF) under one
003     *   or more contributor license agreements.  See the NOTICE file
004     *   distributed with this work for additional information
005     *   regarding copyright ownership.  The ASF licenses this file
006     *   to you under the Apache License, Version 2.0 (the
007     *   "License"); you may not use this file except in compliance
008     *   with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *   Unless required by applicable law or agreed to in writing,
013     *   software distributed under the License is distributed on an
014     *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *   KIND, either express or implied.  See the License for the
016     *   specific language governing permissions and limitations
017     *   under the License.
018     *
019     */
020    package org.apache.directory.server.core.journal;
021    
022    import java.io.File;
023    import java.io.FileOutputStream;
024    import java.io.IOException;
025    import java.io.OutputStreamWriter;
026    import java.io.PrintWriter;
027    import java.io.Writer;
028    
029    import org.apache.directory.server.core.DirectoryService;
030    import org.apache.directory.server.core.LdapPrincipal;
031    import org.apache.directory.shared.ldap.exception.LdapException;
032    import org.apache.directory.shared.ldap.ldif.LdifEntry;
033    import org.apache.directory.shared.ldap.ldif.LdifUtils;
034    
035    /**
036     * 
037      * @org.apache.xbean.XBean
038     *
039     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040     * @version $Rev$, $Date$
041    */
042    public class DefaultJournalStore implements JournalStore
043    {
044        /** The directory where the journal is stored */
045        private File workingDirectory;
046        
047        /** The journal file name */
048        private String fileName;
049        
050        /** The file containing the journal */
051        private File journal;
052        
053        /** The stream used to write data into the journal */
054        private Writer writer;
055    
056        
057        /**
058         * {@inheritDoc}
059         */
060        public void destroy() throws Exception
061        {
062            if ( writer != null )
063            {
064                writer.close();
065            }
066        }
067        
068        
069        /**
070         * Initialize the interceptor
071         */
072        public void init( DirectoryService service ) throws Exception
073        {
074            if ( workingDirectory == null )
075            {
076                workingDirectory = service.getWorkingDirectory();
077            }
078    
079            /** Load or create the journal file */
080            if ( fileName == null )
081            {
082                fileName = "journal.ldif";
083            }
084            
085            journal = new File( workingDirectory, fileName );
086            
087            // The new requests are added at the end of the existing journal
088            writer = new PrintWriter( 
089                new OutputStreamWriter(
090                    new FileOutputStream( journal, true ) ) );
091        }
092        
093        
094        /**
095         * Stores an event into the journal.
096         * 
097         * @param principal The principal who is logging the change
098         * @param revision The operation revision
099         * @param forward The change to log
100         */
101        public boolean log( LdapPrincipal principal, long revision, LdifEntry forward )
102        {
103            synchronized ( writer )
104            {
105                try
106                {
107                    // Write the LdapPrincipal
108                    writer.write( "# principal: " );
109                    writer.write( principal.getName() );
110                    writer.write( '\n' );
111                    
112                    // Write the timestamp
113                    writer.write( "# timestamp: " );
114                    writer.write( Long.toString( System.currentTimeMillis() ) );
115                    writer.write( '\n' );
116                    
117                    // Write the revision
118                    writer.write( "# revision: " );
119                    writer.write( Long.toString( revision ) );
120                    writer.write( "\n" );
121                    
122                    // Write the entry
123                    writer.write( LdifUtils.convertToLdif( forward, 80 ) );
124                    writer.flush();
125                }
126                catch ( LdapException ne )
127                {
128                    return false;
129                }
130                catch ( IOException ioe )
131                {
132                    return false;
133                }
134            }
135            
136            return true;
137        }
138        
139        
140        /**
141         * Records a ack for a change
142         *
143         * @param revision The change revision which is acked
144         * @return <code>true</code> if the ack has been written
145         * @throws Exception if there are problems logging the ack
146         */
147        public boolean ack( long revision )
148        {
149            synchronized ( writer )
150            {
151                try
152                {
153                    // Write the revision
154                    writer.write( "# ack-revision: " );
155                    writer.write( Long.toString( revision ) );
156                    writer.write( "\n\n" );
157    
158                    writer.flush();
159                }
160                catch ( IOException ioe )
161                {
162                    return false;
163                }
164            }
165            
166            return true;
167        }
168        
169        
170        /**
171         * Records a nack for a change
172         *
173         * @param revision The change revision which is nacked
174         * @return <code>true</code> if the nack has been written
175         * @throws Exception if there are problems logging the nack
176         */
177        public boolean nack( long revision )
178        {
179            synchronized ( writer )
180            {
181                try
182                {
183                    // Write the revision
184                    writer.write( "# nack-revision: " );
185                    writer.write( Long.toString( revision ) );
186                    writer.write( "\n\n" );
187    
188                    writer.flush();
189                }
190                catch ( IOException ioe )
191                {
192                    return false;
193                }
194            }
195            
196            return true;
197        }
198    
199        
200        public void sync() throws Exception
201        {
202            // TODO Auto-generated method stub
203            
204        }
205        
206        public long getCurrentRevision()
207        {
208            // TODO Auto-generated method stub
209            return 0;
210        }
211    
212    
213        /**
214         * @return the fileName
215         */
216        public String getFileName()
217        {
218            return fileName;
219        }
220    
221    
222        /**
223         * @param fileName the fileName to set
224         */
225        public void setFileName( String fileName )
226        {
227            this.fileName = fileName;
228        }
229    
230    
231        /**
232         * {@inheritDoc}
233         */
234        public void setWorkingDirectory( String workingDirectoryName )
235        {
236            this.workingDirectory = new File( workingDirectoryName );
237        }
238    }