Das Laden von Dokumenten im jadice web toolkit erfolgt in kundenspezifischen DocumentDataProvidern
. Oft werden dabei Dateien aus einem Archiv ins Filesystem des JWT Servers heruntergeladen und von dort für die Anzeige im Browser eingelesen. Vom Browser wird die aktuell angezeigte Seite und ein konfigurierbares Intervall an umgebenden Seiten angefordert (Lazy Loading). Falls der Benutzer einen Dokumentbereich erst zu einem späteren Zeitpunkt betrachtet, muss die aus dem Archiv heruntergeladene Datei zu diesem späteren Zeitpunkt erneut gelesen werden. Daher wird der zugehörige InputStream
serverseitig gecacht und nicht geschlossen. Erfolgt über eine konfigurierbare Zeitspanne (im Standard 60 Minuten) kein Zugriff mehr auf ein Dokument, werden alle zugehörigen Elemente aus dem Cache entfernt. Muss das Dokument danach erneut gelesen werden, geschieht dies über die recover-Methode des DocumentDataProviders. Dabei wird ein neuer InputStream erzeugt und gecacht.
Parallel dazu gibt es häufig die Anforderung, nach der Bearbeitung eines Dokuments die zugehörige, nicht mehr benötigte Archivdatei aus dem Filesystem des Servers zu löschen. Das Ende der Bearbeitung ist allerdings serverseitig nicht zuverlässig erkennbar. Beispielsweise erhält der Server beim Schließen des Browsertabs keine Benachrichtigung darüber, dass ein in Bearbeitung befindliches Dokument nicht mehr benötigt wird.
Eine Möglichkeit die Anforderung abzubilden, stellt die Verwendung des BufferManagers
dar (seit JWT Version 5.4.12.0). Damit werden Dokumente initial komplett eingelesen und intelligent im Hauptspeicher und einer temporären Datei gepuffert. Sobald im serverseitigen Cache keine Einträge mehr auf das Dokument vorhanden sind (im Standard 60 Minuten nach dem letzten Zugriff), gibt der Buffer Manager automatisch den zugehörigen Pufferbereich zum Überschreiben frei. Heruntergeladene Archivdateien können damit direkt nach dem Einlesen gelöscht werden.
Der Buffer Manager stellt die folgenden Konfigurationsmöglichkeiten zur Verfügung:
- Die Größe des Puffers im Hauptspeicher
Das Verhalten bei der Pufferung sieht folgendermaßen aus:
- falls es einen freien Bereich im Hauptspeicherpuffer gibt, wird dieser verwendet
- falls der Hauptspeicherbereich keinen freien Platz besitzt, wird ein freier Bereich in der Pufferdatei verwendet
- falls weder in Hauptspeicher noch in der Pufferdatei ein freier Bereich existiert, wird die Pufferdatei vergrößert
- die Pufferdatei wird nicht verkleinert
- durch das Wiederbeschreiben freigegebener Bereiche ist Größe der Pufferdatei beschränkt (abhängig vom Nutzungsverhalten)
- beim Neustart des Servers wird eine bestehende Puffderdatei gelöscht und eine neue Pufferdatei mit der Größe 0 angelegt
Näheres zur Arbeitsweise des BufferManager
siehe
https://support.levigo.de/products/jadice/documentplatform/current/german/sect.input.stream.html#sect.input.stream.bufferManager
Step-by-step guide
Hinzufügen der folgenden Maven Dependency
<dependency> <groupId>com.levigo.jadice.documentplatform.core</groupId> <artifactId>jadice-buffer-manager</artifactId> </dependency>
Einmalige Aktivierung des Buffer Managers beim Starten des Servers (z.B. im
ContextListener
)... import com.levigo.jadice.bm.BufferManagerConfigurer; import com.levigo.jadice.bm.internal.DefaultBufferManager; ... private void configureBufferManager() { try { BufferManagerConfigurer.configure().fileStoreStrategy(BufferManagerConfigurer.FileStoreStrategy.ASYNCHRONOUS_FILE_CHANNEL).install(); } catch (JadiceException e) { e.printStackTrace(); } DefaultBufferManager.setEnabled(true); }
Nutzung des Buffer Managers im
DocumentDataProvider
... import com.levigo.jadice.document.io.IOUtils; import com.levigo.jadice.document.io.SeekableInputStream; ... @Override public void read(Reader reader, MyArchiveSource source) throws JadiceException, IOException { // here the file is downloaded from the archive and placed in the file system ... if (!new File(source.getPath()).exists()) throw new IOException("Can't find Resource on Filesystem: " + source.getPath()); try(FileInputStream fis = new FileInputStream(source.getPath())) { SeekableInputStream sis = IOUtils.wrap(fis); IOUtils.drainSynchronously(sis); reader.read(sis); } finally { // delete the file in the filesystem (not required in case of NOT using a FileInputStream!) new File(source.getPath()).delete(); } } @Override public void recover(Reader reader, MyArchiveHandle handle) throws RecoverFailedException, JadiceException { // here the file is downloaded from the archive and placed in the file system ... if (!new File(handle.getPath()).exists()) throw new RecoverFailedException("Can't find Resource on Filesystem: " + handle.getPath()); try(FileInputStream fis = new FileInputStream(handle.getPath())) { SeekableInputStream sis = IOUtils.wrap(fis); IOUtils.drainSynchronously(sis); reader.read(sis); } catch (IOException e) { throw new RecoverFailedException("Can't find Resource on Filesystem: " + handle.getPath()); } finally { // delete the file in the filesystem (not required in case of NOT using a FileInputStream!) new File(source.getPath()).delete(); } } ...
Konfiguration der maximalen Verweildauer von Einträgen im serverseitigen Cache in der Datei
Jadice.properties
... # Defines whether the MaximumAgeExpiryStrategy should be used or not. This # expiry is only affected by the properties jadice.viewer.cache.maxAge and # jadice.viewer.cache.maxAge.timeUnit. All other properties wont influence this # strategy. This strategy expires all entries which are older than the defined # age. Age means the time passed since their last cache access. jadice.viewer.cache.maxAgeExpiryEnabled=true # This sets the max age of cache entries. All cache entries which are older # than the defined age are expired. The unit of the age is configured through # jadice.viewer.cache.maxAge.timeUnit jadice.viewer.cache.maxAge=60 # The TimeUnit for the max age of the cache entries. The string must match an # enum value of java.util.concurrent.TimeUnit. jadice.viewer.cache.maxAge.timeUnit=MINUTES # This sets the number of memory buffers to use. Each memory buffer has a capacity # of 64 KB. When all memory buffers are in use additional data is buffered in a file # located under jadice.viewer.tmps-path bufferManager.memoryBuffers=2000
Related articles