001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.memory;
016    
017    import com.liferay.portal.kernel.concurrent.ConcurrentIdentityHashMap;
018    
019    import java.lang.ref.Reference;
020    import java.lang.ref.ReferenceQueue;
021    
022    import java.util.Map;
023    
024    /**
025     * @author Shuyang Zhou
026     */
027    public class FinalizeManager {
028    
029            public static final ReferenceFactory PHANTOM_REFERENCE_FACTORY =
030                    new ReferenceFactory() {
031    
032                            @Override
033                            public <T> Reference<T> createReference(
034                                    T reference, ReferenceQueue<? super T> referenceQueue) {
035    
036                                    return new EqualityPhantomReference<T>(
037                                            reference, referenceQueue) {
038    
039                                            @Override
040                                            public void clear() {
041                                                    _finalizeActions.remove(this);
042    
043                                                    super.clear();
044                                            }
045    
046                                    };
047                            }
048    
049                    };
050    
051            public static final ReferenceFactory SOFT_REFERENCE_FACTORY =
052                    new ReferenceFactory() {
053    
054                            @Override
055                            public <T> Reference<T> createReference(
056                                    T reference, ReferenceQueue<? super T> referenceQueue) {
057    
058                                    return new EqualitySoftReference<T>(reference, referenceQueue) {
059    
060                                            @Override
061                                            public void clear() {
062                                                    _finalizeActions.remove(this);
063    
064                                                    super.clear();
065                                            }
066    
067                                    };
068                            }
069    
070                    };
071    
072            public static final boolean THREAD_ENABLED = Boolean.getBoolean(
073                    FinalizeManager.class.getName() + ".thread.enabled");
074    
075            public static final ReferenceFactory WEAK_REFERENCE_FACTORY =
076                    new ReferenceFactory() {
077    
078                            @Override
079                            public <T> Reference<T> createReference(
080                                    T reference, ReferenceQueue<? super T> referenceQueue) {
081    
082                                    return new EqualityWeakReference<T>(reference, referenceQueue) {
083    
084                                            @Override
085                                            public void clear() {
086                                                    _finalizeActions.remove(this);
087    
088                                                    super.clear();
089                                            }
090    
091                                    };
092                            }
093    
094                    };
095    
096            static {
097                    if (THREAD_ENABLED) {
098                            Thread thread = new FinalizeThread("Finalize Thread");
099    
100                            thread.setContextClassLoader(
101                                    FinalizeManager.class.getClassLoader());
102    
103                            thread.setDaemon(true);
104    
105                            thread.start();
106                    }
107            }
108    
109            public static <T> Reference<T> register(
110                    T reference, FinalizeAction finalizeAction,
111                    ReferenceFactory referenceFactory) {
112    
113                    Reference<T> newReference = referenceFactory.createReference(
114                            reference, _referenceQueue);
115    
116                    _finalizeActions.put(newReference, finalizeAction);
117    
118                    if (!THREAD_ENABLED) {
119                            _pollingCleanup();
120                    }
121    
122                    return newReference;
123            }
124    
125            public interface ReferenceFactory {
126    
127                    public <T> Reference<T> createReference(
128                            T realReference, ReferenceQueue<? super T> referenceQueue);
129    
130            }
131    
132            private static void _finalizeReference(
133                    Reference<? extends Object> reference) {
134    
135                    FinalizeAction finalizeAction = _finalizeActions.remove(reference);
136    
137                    if (finalizeAction != null) {
138                            try {
139                                    finalizeAction.doFinalize(reference);
140                            }
141                            finally {
142                                    reference.clear();
143                            }
144                    }
145            }
146    
147            private static void _pollingCleanup() {
148                    Reference<? extends Object> reference = null;
149    
150                    while ((reference = _referenceQueue.poll()) != null) {
151                            _finalizeReference(reference);
152                    }
153            }
154    
155            private static final Map<Reference<?>, FinalizeAction> _finalizeActions =
156                    new ConcurrentIdentityHashMap<>();
157            private static final ReferenceQueue<Object> _referenceQueue =
158                    new ReferenceQueue<>();
159    
160            private static class FinalizeThread extends Thread {
161    
162                    public FinalizeThread(String name) {
163                            super(name);
164                    }
165    
166                    @Override
167                    public void run() {
168                            while (true) {
169                                    try {
170                                            _finalizeReference(_referenceQueue.remove());
171                                    }
172                                    catch (InterruptedException ie) {
173                                    }
174                            }
175                    }
176    
177            }
178    
179    }