View Javadoc
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,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.server.core.journal;
21  
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.PrintWriter;
26  import java.io.Writer;
27  import java.nio.charset.StandardCharsets;
28  import java.nio.file.Files;
29  import java.nio.file.StandardOpenOption;
30  
31  import org.apache.directory.api.ldap.model.exception.LdapException;
32  import org.apache.directory.api.ldap.model.ldif.LdifEntry;
33  import org.apache.directory.api.ldap.model.ldif.LdifUtils;
34  import org.apache.directory.server.core.api.DirectoryService;
35  import org.apache.directory.server.core.api.LdapPrincipal;
36  import org.apache.directory.server.core.api.journal.JournalStore;
37  
38  
39  /**
40   * The default Journal Store implementation. It creates a file on disk in which
41   * the logs will be appended.
42   *  
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44  */
45  public class DefaultJournalStore implements JournalStore
46  {
47      /** The directory where the journal is stored */
48      private File workingDirectory;
49  
50      /** The journal file name */
51      private String fileName;
52  
53      /** The file containing the journal */
54      private File journal;
55  
56      /** The stream used to write data into the journal */
57      private Writer writer;
58  
59  
60      /**
61       * {@inheritDoc}
62       */
63      @Override
64      public void destroy() throws IOException
65      {
66          if ( writer != null )
67          {
68              writer.close();
69          }
70      }
71  
72  
73      /**
74       * Initialize the interceptor
75       */
76      @Override
77      public void init( DirectoryService service ) throws IOException
78      {
79          if ( workingDirectory == null )
80          {
81              workingDirectory = service.getInstanceLayout().getLogDirectory();
82          }
83  
84          /** Load or create the journal file */
85          if ( fileName == null )
86          {
87              fileName = "journal.ldif";
88          }
89  
90          journal = new File( workingDirectory, fileName );
91  
92          // The new requests are added at the end of the existing journal
93          writer = new PrintWriter(
94              Files.newBufferedWriter( journal.toPath(), StandardCharsets.UTF_8, StandardOpenOption.APPEND ) );
95      }
96  
97  
98      /**
99       * Stores an event into the journal.
100      * 
101      * @param principal The principal who is logging the change
102      * @param revision The operation revision
103      * @param forward The change to log
104      */
105     @Override
106     public boolean log( LdapPrincipal principal, long revision, LdifEntry forward )
107     {
108         synchronized ( writer )
109         {
110             try
111             {
112                 // Write the LdapPrincipal
113                 writer.write( "# principal: " );
114                 writer.write( principal.getName() );
115                 writer.write( '\n' );
116 
117                 // Write the timestamp
118                 writer.write( "# timestamp: " );
119                 writer.write( Long.toString( System.currentTimeMillis() ) );
120                 writer.write( '\n' );
121 
122                 // Write the revision
123                 writer.write( "# revision: " );
124                 writer.write( Long.toString( revision ) );
125                 writer.write( "\n" );
126 
127                 // Write the entry
128                 writer.write( LdifUtils.convertToLdif( forward, 80 ) );
129                 writer.flush();
130             }
131             catch ( LdapException | IOException e )
132             {
133                 return false;
134             }
135         }
136 
137         return true;
138     }
139 
140 
141     /**
142      * Records a ack for a change
143      *
144      * @param revision The change revision which is acked
145      * @return <code>true</code> if the ack has been written
146      */
147     @Override
148     public boolean ack( long revision )
149     {
150         synchronized ( writer )
151         {
152             try
153             {
154                 // Write the revision
155                 writer.write( "# ack-revision: " );
156                 writer.write( Long.toString( revision ) );
157                 writer.write( "\n\n" );
158 
159                 writer.flush();
160             }
161             catch ( IOException ioe )
162             {
163                 return false;
164             }
165         }
166 
167         return true;
168     }
169 
170 
171     /**
172      * Records a nack for a change
173      *
174      * @param revision The change revision which is nacked
175      * @return <code>true</code> if the nack has been written
176      */
177     @Override
178     public boolean nack( long revision )
179     {
180         synchronized ( writer )
181         {
182             try
183             {
184                 // Write the revision
185                 writer.write( "# nack-revision: " );
186                 writer.write( Long.toString( revision ) );
187                 writer.write( "\n\n" );
188 
189                 writer.flush();
190             }
191             catch ( IOException ioe )
192             {
193                 return false;
194             }
195         }
196 
197         return true;
198     }
199 
200 
201     @Override
202     public void sync() throws IOException
203     {
204         // TODO Auto-generated method stub
205 
206     }
207 
208 
209     @Override
210     public long getCurrentRevision()
211     {
212         // TODO Auto-generated method stub
213         return 0;
214     }
215 
216 
217     /**
218      * @return the fileName
219      */
220     public String getFileName()
221     {
222         return fileName;
223     }
224 
225 
226     /**
227      * @param fileName the fileName to set
228      */
229     @Override
230     public void setFileName( String fileName )
231     {
232         this.fileName = fileName;
233     }
234 
235 
236     /**
237      * {@inheritDoc}
238      */
239     @Override
240     public void setWorkingDirectory( String workingDirectoryName )
241     {
242         this.workingDirectory = new File( workingDirectoryName );
243     }
244 }