001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU General
007: * Public License Version 2 only ("GPL") or the Common Development and Distribution
008: * License("CDDL") (collectively, the "License"). You may not use this file except in
009: * compliance with the License. You can obtain a copy of the License at
010: * http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. See the
011: * License for the specific language governing permissions and limitations under the
012: * License. When distributing the software, include this License Header Notice in
013: * each file and include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun
014: * designates this particular file as subject to the "Classpath" exception as
015: * provided by Sun in the GPL Version 2 section of the License file that
016: * accompanied this code. If applicable, add the following below the License Header,
017: * with the fields enclosed by brackets [] replaced by your own identifying
018: * information: "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Contributor(s):
021: *
022: * The Original Software is NetBeans. The Initial Developer of the Original Software
023: * is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun Microsystems, Inc. All
024: * Rights Reserved.
025: *
026: * If you wish your version of this file to be governed by only the CDDL or only the
027: * GPL Version 2, indicate your decision by adding "[Contributor] elects to include
028: * this software in this distribution under the [CDDL or GPL Version 2] license." If
029: * you do not indicate a single choice of license, a recipient has the option to
030: * distribute your version of this file under either the CDDL, the GPL Version 2 or
031: * to extend the choice of license to its licensees as provided above. However, if
032: * you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then
033: * the option applies only if the new code is made subject to such option by the
034: * copyright holder.
035: */
036:
037: package org.netbeans.installer.downloader.queue;
038:
039: import org.netbeans.installer.downloader.Pumping;
040: import org.netbeans.installer.downloader.PumpingsQueue;
041: import org.netbeans.installer.downloader.DownloadListener;
042: import org.netbeans.installer.downloader.impl.PumpingImpl;
043: import org.netbeans.installer.utils.LogManager;
044: import org.netbeans.installer.utils.exceptions.ParseException;
045: import org.netbeans.installer.utils.exceptions.UnexpectedExceptionError;
046: import org.netbeans.installer.utils.xml.DomUtil;
047: import org.netbeans.installer.utils.xml.visitors.DomVisitor;
048: import org.netbeans.installer.utils.xml.visitors.RecursiveDomVisitor;
049: import org.w3c.dom.Document;
050: import org.w3c.dom.Element;
051: import java.io.File;
052: import java.io.IOException;
053: import java.lang.ref.WeakReference;
054: import java.lang.reflect.InvocationTargetException;
055: import java.lang.reflect.Method;
056: import java.util.ArrayList;
057: import java.util.HashMap;
058: import java.util.List;
059: import java.util.Map;
060:
061: /**
062: * @author Danila_Dugurov
063: */
064:
065: public abstract class QueueBase implements PumpingsQueue {
066:
067: /////////////////////////////////////////////////////////////////////////////////
068: // Static
069: /**
070: * @noinspection unchecked
071: */
072: private static final WeakReference<DownloadListener>[] EMPTY_ARRAY = new WeakReference[0];
073:
074: /////////////////////////////////////////////////////////////////////////////////
075: // Instance
076: private final List<WeakReference<DownloadListener>> listeners;
077:
078: protected final Map<String, PumpingImpl> id2Pumping = new HashMap<String, PumpingImpl>();
079:
080: protected File stateFile;
081:
082: protected QueueBase(File stateFile) {
083: this .stateFile = stateFile;
084: if (stateFile.exists()) {
085: load();
086: LogManager.log("queue state was load from file: "
087: + stateFile);
088: } else
089: LogManager.log("file not exist, queue is empty!");
090: listeners = new ArrayList<WeakReference<DownloadListener>>(3);
091: }
092:
093: public synchronized void addListener(DownloadListener listener) {
094: if (!contains(listener)) {
095: listeners
096: .add(new WeakReference<DownloadListener>(listener));
097: }
098: }
099:
100: private boolean contains(DownloadListener listener) {
101: for (WeakReference<DownloadListener> weak : listeners) {
102: final DownloadListener listen = weak.get();
103: if (listen != null && listen.equals(listener))
104: return true;
105: }
106: return false;
107: }
108:
109: public Pumping getById(String id) {
110: return id2Pumping.get(id);
111: }
112:
113: public Pumping[] toArray() {
114: return id2Pumping.values().toArray(new Pumping[0]);
115: }
116:
117: public void fire(String methodName, Object... args) {
118: final List<Class> argsClasses = new ArrayList<Class>(
119: args.length);
120: for (Object arg : args) {
121: argsClasses.add(arg.getClass());
122: }
123: try {
124: final Method method = DownloadListener.class.getMethod(
125: methodName, argsClasses.toArray(new Class[0]));
126: notifyListeners(method, args);
127: } catch (NoSuchMethodException ex) {
128: throw new UnexpectedExceptionError(
129: "Listener contract was changed", ex);
130: }
131: }
132:
133: private synchronized void notifyListeners(Method mehtod,
134: Object... args) {
135: WeakReference<DownloadListener>[] stub = listeners
136: .toArray(EMPTY_ARRAY);
137: for (WeakReference<DownloadListener> ref : stub) {
138: final DownloadListener listener = ref.get();
139: if (listener == null)
140: continue;
141: try {
142: mehtod.invoke(listener, args);
143: } catch (IllegalAccessException ignored) {
144: LogManager.log(ignored);
145: } catch (InvocationTargetException ignored) {
146: //undeline throw an exception.
147: //It's not headache of queue if listener throws exceptions - just log it for debug purpose
148: LogManager.log(ignored);
149: }
150: }
151: }
152:
153: protected void load() {
154: try {
155: Document queueState = DomUtil.parseXmlFile(stateFile);
156: final DomVisitor visitor = new RecursiveDomVisitor() {
157: public void visit(Element element) {
158: if ("pumping".equals(element.getNodeName())) {
159: final PumpingImpl newOne = new PumpingImpl(
160: QueueBase.this );
161: newOne.readXML(element);
162: id2Pumping.put(newOne.getId(), newOne);
163: } else
164: super .visit(element);
165: }
166: };
167: visitor.visit(queueState);
168: } catch (ParseException ex) {
169: LogManager
170: .log("fail to load queue state - parsing error occurs");
171: } catch (IOException ex) {
172: LogManager
173: .log("I/O error during loading. queue is empty now");
174: }
175: }
176:
177: public synchronized void dump() {
178: try {
179: final Document document = DomUtil
180: .parseXmlFile("<queueState/>");
181: final Element root = document.getDocumentElement();
182: for (Pumping puming : toArray()) {
183: DomUtil.addChild(root, (PumpingImpl) puming);
184: }
185: DomUtil.writeXmlFile(document, stateFile);
186: } catch (ParseException wontHappend) {
187: LogManager.log(wontHappend);
188: } catch (IOException io) {
189: LogManager.log("fail to dump - i/o error occures");
190: LogManager.log(io);
191: }
192: }
193: }
|