forked from qzind/tray
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Caching for CUPS status performance (#6)
Caching for CUPS status performance --------- Co-authored-by: Vzor- <Kyle@Berezin.com>
- Loading branch information
Showing
4 changed files
with
249 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package qz.common; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import java.util.function.Supplier; | ||
|
||
/** | ||
* A generic class that encapsulates an object for caching. The cached object | ||
* will be refreshed automatically when accessed after its lifespan has expired. | ||
* | ||
* @param <T> The type of object to be cached. | ||
*/ | ||
public class CachedObject<T> { | ||
public static final long DEFAULT_LIFESPAN = 5000; // in milliseconds | ||
T lastObject; | ||
Supplier<T> supplier; | ||
private long timestamp; | ||
private long lifespan; | ||
|
||
/** | ||
* Creates a new CachedObject with a default lifespan of 5000 milliseconds | ||
* | ||
* @param supplier The function to pull new values from | ||
*/ | ||
public CachedObject(Supplier<T> supplier) { | ||
this(supplier, DEFAULT_LIFESPAN); | ||
} | ||
|
||
/** | ||
* Creates a new CachedObject | ||
* | ||
* @param supplier The function to pull new values from | ||
* @param lifespan The lifespan of the cached object in milliseconds | ||
*/ | ||
public CachedObject(Supplier<T> supplier, long lifespan) { | ||
this.supplier = supplier; | ||
setLifespan(lifespan); | ||
timestamp = Long.MIN_VALUE; // System.nanoTime() can be negative, MIN_VALUE guarantees a first-run. | ||
} | ||
|
||
/** | ||
* Registers a new supplier for the CachedObject | ||
* | ||
* @param supplier The function to pull new values from | ||
*/ | ||
public void registerSupplier(Supplier<T> supplier) { | ||
this.supplier = supplier; | ||
} | ||
|
||
/** | ||
* Sets the lifespan of the cached object | ||
* | ||
* @param milliseconds The lifespan of the cached object in milliseconds | ||
*/ | ||
public void setLifespan(long milliseconds) { | ||
lifespan = Math.max(0, milliseconds); // prevent overflow | ||
} | ||
|
||
/** | ||
* Retrieves the cached object. | ||
* If the cached object's lifespan has expired, it gets refreshed before being returned. | ||
* | ||
* @return The cached object | ||
*/ | ||
public T get() { | ||
return get(false); | ||
} | ||
|
||
/** | ||
* Retrieves the cached object. | ||
* If the cached object's lifespan is expired or forceRefresh is true, it gets refreshed before being returned. | ||
* | ||
* @param forceRefresh If true, the cached object will be refreshed before being returned regardless of its lifespan | ||
* @return The cached object | ||
*/ | ||
public T get(boolean forceRefresh) { | ||
long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); | ||
// check lifespan | ||
if (forceRefresh || (timestamp + lifespan <= now)) { | ||
timestamp = now; | ||
lastObject = supplier.get(); | ||
} | ||
return lastObject; | ||
} | ||
|
||
// Test | ||
public static void main(String ... args) throws InterruptedException { | ||
final AtomicInteger testInt = new AtomicInteger(0); | ||
|
||
CachedObject<Integer> cachedString = new CachedObject<>(testInt::incrementAndGet); | ||
for(int i = 0; i < 100; i++) { | ||
Thread.sleep(1500); | ||
System.out.println(cachedString.get()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package qz.printer.info; | ||
|
||
import qz.common.CachedObject; | ||
|
||
import javax.print.*; | ||
import javax.print.attribute.Attribute; | ||
import javax.print.attribute.AttributeSet; | ||
import javax.print.attribute.PrintServiceAttribute; | ||
import javax.print.attribute.PrintServiceAttributeSet; | ||
import javax.print.event.PrintServiceAttributeListener; | ||
import java.util.HashMap; | ||
import java.util.function.Supplier; | ||
|
||
public class CachedPrintService implements PrintService { | ||
public PrintService innerPrintService; | ||
// PrintService.getName() is slow, use a cache instead per JDK-7001133 | ||
// TODO: Remove this comment when upstream bug report is filed | ||
private static final long lifespan = CachedObject.DEFAULT_LIFESPAN; | ||
private static final CachedObject<PrintService> cachedDefault = new CachedObject<>(CachedPrintService::innerLookupDefaultPrintService, lifespan); | ||
private static final CachedObject<PrintService[]> cachedPrintServices = new CachedObject<>(CachedPrintService::innerLookupPrintServices, lifespan); | ||
private final CachedObject<String> cachedName; | ||
private final CachedObject<PrintServiceAttributeSet> cachedAttributeSet; | ||
private final HashMap<Class<?>, CachedObject<?>> cachedAttributes = new HashMap<>(); | ||
|
||
public static PrintService lookupDefaultPrintService() { | ||
return cachedDefault.get(); | ||
} | ||
|
||
public static PrintService[] lookupPrintServices() { | ||
return cachedPrintServices.get(); | ||
} | ||
|
||
private static PrintService innerLookupDefaultPrintService() { | ||
return new CachedPrintService(PrintServiceLookup.lookupDefaultPrintService()); | ||
} | ||
|
||
private static PrintService[] innerLookupPrintServices() { | ||
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null); | ||
for (int i = 0; i < printServices.length; i++) { | ||
printServices[i] = new CachedPrintService(printServices[i]); | ||
} | ||
return printServices; | ||
} | ||
|
||
public CachedPrintService(PrintService printService) { | ||
innerPrintService = printService; | ||
cachedName = new CachedObject<>(innerPrintService::getName, lifespan); | ||
cachedAttributeSet = new CachedObject<>(innerPrintService::getAttributes, lifespan); | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return cachedName.get(); | ||
} | ||
|
||
@Override | ||
public DocPrintJob createPrintJob() { | ||
return innerPrintService.createPrintJob(); | ||
} | ||
|
||
@Override | ||
public void addPrintServiceAttributeListener(PrintServiceAttributeListener listener) { | ||
innerPrintService.addPrintServiceAttributeListener(listener); | ||
} | ||
|
||
@Override | ||
public void removePrintServiceAttributeListener(PrintServiceAttributeListener listener) { | ||
innerPrintService.removePrintServiceAttributeListener(listener); | ||
} | ||
|
||
@Override | ||
public PrintServiceAttributeSet getAttributes() { | ||
return cachedAttributeSet.get(); | ||
} | ||
|
||
@Override | ||
public <T extends PrintServiceAttribute> T getAttribute(Class<T> category) { | ||
if (!cachedAttributes.containsKey(category)) { | ||
Supplier<T> supplier = () -> innerPrintService.getAttribute(category); | ||
CachedObject<T> cachedObject = new CachedObject<>(supplier, lifespan); | ||
cachedAttributes.put(category, cachedObject); | ||
} | ||
return category.cast(cachedAttributes.get(category).get()); | ||
} | ||
|
||
@Override | ||
public DocFlavor[] getSupportedDocFlavors() { | ||
return innerPrintService.getSupportedDocFlavors(); | ||
} | ||
|
||
@Override | ||
public boolean isDocFlavorSupported(DocFlavor flavor) { | ||
return innerPrintService.isDocFlavorSupported(flavor); | ||
} | ||
|
||
@Override | ||
public Class<?>[] getSupportedAttributeCategories() { | ||
return innerPrintService.getSupportedAttributeCategories(); | ||
} | ||
|
||
@Override | ||
public boolean isAttributeCategorySupported(Class<? extends Attribute> category) { | ||
return innerPrintService.isAttributeCategorySupported(category); | ||
} | ||
|
||
@Override | ||
public Object getDefaultAttributeValue(Class<? extends Attribute> category) { | ||
return innerPrintService.getDefaultAttributeValue(category); | ||
} | ||
|
||
@Override | ||
public Object getSupportedAttributeValues(Class<? extends Attribute> category, DocFlavor flavor, AttributeSet attributes) { | ||
return innerPrintService.getSupportedAttributeValues(category, flavor, attributes); | ||
} | ||
|
||
@Override | ||
public boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor, AttributeSet attributes) { | ||
return innerPrintService.isAttributeValueSupported(attrval, flavor, attributes); | ||
} | ||
|
||
@Override | ||
public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) { | ||
return innerPrintService.getUnsupportedAttributes(flavor, attributes); | ||
} | ||
|
||
@Override | ||
public ServiceUIFactory getServiceUIFactory() { | ||
return innerPrintService.getServiceUIFactory(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters