1 /*
2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.font;
27
28 import java.io.File;
29 import java.io.OutputStream;
30 import java.security.AccessController;
31 import java.security.PrivilegedAction;
32 import java.util.HashMap;
33 import java.util.Map;
34 import java.util.concurrent.Semaphore;
35 import java.util.concurrent.TimeUnit;
36
37 import sun.awt.AppContext;
38 import sun.misc.ThreadGroupUtils;
39
40 public class CreatedFontTracker {
41
42 public static final int MAX_FILE_SIZE = 32 * 1024 * 1024;
43 public static final int MAX_TOTAL_BYTES = 10 * MAX_FILE_SIZE;
44
45 static CreatedFontTracker tracker;
46 int numBytes;
47
48 public static synchronized CreatedFontTracker getTracker() {
49 if (tracker == null) {
50 tracker = new CreatedFontTracker();
51 }
52 return tracker;
53 }
54
55 private CreatedFontTracker() {
56 numBytes = 0;
57 }
58
59 public synchronized int getNumBytes() {
60 return numBytes;
61 }
62
63 public synchronized void addBytes(int sz) {
64 numBytes += sz;
65 }
66
67 public synchronized void subBytes(int sz) {
68 numBytes -= sz;
69 }
70
71 /**
72 * Returns an AppContext-specific counting semaphore.
73 */
74 private static synchronized Semaphore getCS() {
75 final AppContext appContext = AppContext.getAppContext();
76 Semaphore cs = (Semaphore) appContext.get(CreatedFontTracker.class);
77 if (cs == null) {
78 // Make a semaphore with 5 permits that obeys the first-in first-out
79 // granting of permits.
80 cs = new Semaphore(5, true);
81 appContext.put(CreatedFontTracker.class, cs);
82 }
83 return cs;
84 }
85
86 public boolean acquirePermit() throws InterruptedException {
87 // This does a timed-out wait.
88 return getCS().tryAcquire(120, TimeUnit.SECONDS);
89 }
90
91 public void releasePermit() {
92 getCS().release();
93 }
94
95 public void add(File file) {
96 TempFileDeletionHook.add(file);
97 }
98
99 public void set(File file, OutputStream os) {
100 TempFileDeletionHook.set(file, os);
101 }
102
103 public void remove(File file) {
104 TempFileDeletionHook.remove(file);
105 }
106
107 /**
108 * Helper class for cleanup of temp files created while processing fonts.
109 * Note that this only applies to createFont() from an InputStream object.
110 */
111 private static class TempFileDeletionHook {
112 private static HashMap<File, OutputStream> files = new HashMap<>();
113
114 private static Thread t = null;
115 static void init() {
116 if (t == null) {
117 // Add a shutdown hook to remove the temp file.
118 AccessController.doPrivileged(
119 (PrivilegedAction<Void>) () -> {
120 /* The thread must be a member of a thread group
121 * which will not get GCed before VM exit.
122 * Make its parent the top-level thread group.
123 */
124 ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup();
125 t = new Thread(rootTG, TempFileDeletionHook::runHooks);
126 t.setContextClassLoader(null);
127 Runtime.getRuntime().addShutdownHook(t);
128 return null;
129 });
130 }
131 }
132
133 private TempFileDeletionHook() {}
134
135 static synchronized void add(File file) {
136 init();
137 files.put(file, null);
138 }
139
140 static synchronized void set(File file, OutputStream os) {
141 files.put(file, os);
142 }
143
144 static synchronized void remove(File file) {
145 files.remove(file);
146 }
147
148 static synchronized void runHooks() {
149 if (files.isEmpty()) {
150 return;
151 }
152
153 for (Map.Entry<File, OutputStream> entry : files.entrySet()) {
154 // Close the associated output stream, and then delete the file.
155 try {
156 if (entry.getValue() != null) {
157 entry.getValue().close();
158 }
159 } catch (Exception e) {}
160 entry.getKey().delete();
161 }
162 }
163 }
164 }
--- EOF ---