Example usage for java.util.concurrent ArrayBlockingQueue add

List of usage examples for java.util.concurrent ArrayBlockingQueue add

Introduction

In this page you can find the example usage for java.util.concurrent ArrayBlockingQueue add.

Prototype

public boolean add(E e) 

Source Link

Document

Inserts the specified element at the tail of this queue if it is possible to do so immediately without exceeding the queue's capacity, returning true upon success and throwing an IllegalStateException if this queue is full.

Usage

From source file:Main.java

public static void main(String[] argv) throws Exception {
    int capacity = 10;
    ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(capacity);

    for (int i = 0; i < 10; i++) {
        queue.add(i);
    }/*  ww  w.  jav  a  2s .  c o m*/

    System.out.println(queue.remove(0));
    System.out.println(queue);
}

From source file:Main.java

public static void main(String[] argv) throws Exception {
    int capacity = 100;
    ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(capacity);

    for (int i = 0; i < 100; i++) {
        queue.add(i);
    }/*from  w w w  . j a va2  s . c  o m*/
    System.out.println(queue.contains(5));
    queue.clear();
    System.out.println(queue.contains(5));
}

From source file:Main.java

public static void main(String[] argv) throws Exception {
    int capacity = 10;
    ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(capacity);

    for (int i = 0; i < 10; i++) {
        queue.add(i);
    }//from   www  . java  2s . c o m
    Iterator<Integer> it = queue.iterator();
    while (it.hasNext()) {
        System.out.println(it.next());
    }
}

From source file:org.kchine.rpf.db.MainNodeManager.java

private static void createTask() {
    try {/*from w  w w  .j  av a  2  s  .c o m*/
        System.out.println(" create worker round at " + new Date());
        long T1 = System.currentTimeMillis();

        final ArrayBlockingQueue<String> indexesQueue = new ArrayBlockingQueue<String>(200);

        Vector<NodeDataDB> nodes = _registry.getNodeData("");
        for (int i = 0; i < nodes.size(); ++i) {
            final String nodeName = nodes.elementAt(i).getNodeName();
            String nodeIp = nodes.elementAt(i).getHostIp();
            String nodePrefix = nodes.elementAt(i).getPoolPrefix();

            Vector<HashMap<String, Object>> servants = _registry.getTableData("SERVANTS", "NODE_NAME='"
                    + nodeName + "'" + " OR (HOST_IP='" + nodeIp + "' AND NAME like '" + nodePrefix + "%')");

            final int missing = nodes.elementAt(i).getServantNbrMin() - servants.size();
            if (missing > 0) {
                System.out.println("Node<" + nodeName + "> missing :" + missing);
                for (int j = 0; j < missing; ++j) {
                    indexesQueue.add(nodeName);
                }
            }
        }

        Thread[] t = new Thread[10];
        for (int i = 0; i < t.length; ++i) {
            t[i] = new Thread(new Runnable() {
                public void run() {

                    while (true) {

                        if (indexesQueue.isEmpty())
                            break;
                        try {
                            if (_nodeData == null) {
                                if (!indexesQueue.isEmpty()) {
                                    String nodeName = indexesQueue.poll();
                                    if (nodeName != null) {
                                        try {
                                            _registry.lookup(
                                                    System.getProperty("node.manager.name") + '_' + nodeName);
                                        } catch (NotBoundException nbe) {
                                            NodeManager _manager = (NodeManager) _registry
                                                    .lookup(System.getProperty("node.manager.name"));
                                            ManagedServant ms = _manager.createServant(nodeName);
                                            System.out.println(ms + "  successfully created");
                                        }
                                    }
                                }
                            } else {

                                if (!indexesQueue.isEmpty()) {
                                    String nodeName = indexesQueue.poll();
                                    if (nodeName != null && nodeName.equals(_nodeData.getNodeName())) {
                                        NodeManager _manager = (NodeManager) _registry.lookup(_nodeManagerName);
                                        ManagedServant ms = _manager.createServant(nodeName);
                                        System.out.println(ms + "  successfully created");
                                    }
                                }

                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                Thread.sleep(500);
                            } catch (Exception e) {
                            }
                        }
                    }

                }
            });

            t[i].start();

        }

        for (int i = 0; i < t.length; ++i) {
            t[i].join();
        }

        System.out
                .println("Last create servants round took :" + (System.currentTimeMillis() - T1) + " millisec");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

From source file:org.datacleaner.api.AnalyzerResultFutureTest.java

public void testMultiThreadedListenerScenario() throws Exception {
    final int threadCount = 10;

    final Thread[] threads = new Thread[threadCount];
    @SuppressWarnings({ "unchecked" })
    final Listener<NumberResult>[] listeners = new Listener[threadCount];
    final ArrayBlockingQueue<Object> resultQueue = new ArrayBlockingQueue<>(threadCount);

    for (int i = 0; i < listeners.length; i++) {
        listeners[i] = new Listener<NumberResult>() {
            @Override//from w w  w  .j av  a 2s.c o m
            public void onSuccess(NumberResult result) {
                resultQueue.add(result);
            }

            @Override
            public void onError(RuntimeException error) {
                resultQueue.add(error);
            }
        };
    }

    final Ref<NumberResult> resultRef = new LazyRef<NumberResult>() {
        @Override
        protected NumberResult fetch() throws Throwable {
            final long randomSleepTime = (long) (1000 * Math.random());
            Thread.sleep(randomSleepTime);
            return new NumberResult(43);
        }
    };

    final AnalyzerResultFuture<NumberResult> future = new AnalyzerResultFutureImpl<>("foo", resultRef);

    for (int i = 0; i < threads.length; i++) {
        final Listener<NumberResult> listener = listeners[i];
        threads[i] = new Thread() {
            @Override
            public void run() {
                future.addListener(listener);
            }
        };
    }

    final int halfOfTheThreads = threads.length / 2;
    for (int i = 0; i < halfOfTheThreads; i++) {
        threads[i].start();
    }
    for (int i = 0; i < halfOfTheThreads; i++) {
        threads[i].join();
    }

    future.get();

    // to avoid any race conditions we use the drainTo method before calling
    // toString().
    final List<Object> result = new ArrayList<>();
    resultQueue.drainTo(result);

    assertEquals("[43, 43, 43, 43, 43]", result.toString());
    assertEquals(halfOfTheThreads, result.size());

    for (int i = halfOfTheThreads; i < threads.length; i++) {
        threads[i].start();
    }
    for (int i = halfOfTheThreads; i < threads.length; i++) {
        threads[i].join();
    }

    resultQueue.drainTo(result);

    assertEquals("[43, 43, 43, 43, 43, 43, 43, 43, 43, 43]", result.toString());
    assertEquals(threads.length, result.size());
}

From source file:com.twofortyfouram.locale.sdk.host.test.Junit4SupportLoaderTestCase.java

/**
 * Runs a Loader synchronously and returns the result of the load. The loader will
 * be started, stopped, and destroyed by this method so it cannot be reused.
 *
 * @param loader The loader to run synchronously
 * @return The result from the loader//ww  w  . ja  va 2s .com
 */
public <T> T getLoaderResultSynchronously(final Loader<T> loader) {
    // The test thread blocks on this queue until the loader puts it's result in
    final ArrayBlockingQueue<T> queue = new ArrayBlockingQueue<T>(1);

    // This callback runs on the "main" thread and unblocks the test thread
    // when it puts the result into the blocking queue
    final Loader.OnLoadCompleteListener<T> listener = new Loader.OnLoadCompleteListener<T>() {
        @Override
        public void onLoadComplete(Loader<T> completedLoader, T data) {
            // Shut the loader down
            completedLoader.unregisterListener(this);
            completedLoader.stopLoading();
            completedLoader.reset();

            // Store the result, unblocking the test thread
            queue.add(data);
        }
    };

    // This handler runs on the "main" thread of the process since AsyncTask
    // is documented as needing to run on the main thread and many Loaders use
    // AsyncTask
    final Handler mainThreadHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            loader.registerListener(0, listener);
            loader.startLoading();
        }
    };

    // Ask the main thread to start the loading process
    mainThreadHandler.sendEmptyMessage(0);

    // Block on the queue waiting for the result of the load to be inserted
    T result;
    while (true) {
        try {
            result = queue.take();
            break;
        } catch (InterruptedException e) {
            throw new RuntimeException("waiting thread interrupted", e);
        }
    }

    return result;
}

From source file:org.mozilla.gecko.background.fxa.TestAccountLoader.java

/**
 * Runs a Loader synchronously and returns the result of the load. The loader will
 * be started, stopped, and destroyed by this method so it cannot be reused.
 *
 * @param loader The loader to run synchronously
 * @return The result from the loader//w  ww  .  j  av  a  2 s . c om
 */
public <T> T getLoaderResultSynchronously(final Loader<T> loader) {
    // The test thread blocks on this queue until the loader puts it's result in
    final ArrayBlockingQueue<AtomicReference<T>> queue = new ArrayBlockingQueue<AtomicReference<T>>(1);

    // This callback runs on the "main" thread and unblocks the test thread
    // when it puts the result into the blocking queue
    final OnLoadCompleteListener<T> listener = new OnLoadCompleteListener<T>() {
        @Override
        public void onLoadComplete(Loader<T> completedLoader, T data) {
            // Shut the loader down
            completedLoader.unregisterListener(this);
            completedLoader.stopLoading();
            completedLoader.reset();
            // Store the result, unblocking the test thread
            queue.add(new AtomicReference<T>(data));
        }
    };

    // This handler runs on the "main" thread of the process since AsyncTask
    // is documented as needing to run on the main thread and many Loaders use
    // AsyncTask
    final Handler mainThreadHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            loader.registerListener(0, listener);
            loader.startLoading();
        }
    };

    // Ask the main thread to start the loading process
    mainThreadHandler.sendEmptyMessage(0);

    // Block on the queue waiting for the result of the load to be inserted
    T result;
    while (true) {
        try {
            result = queue.take().get();
            break;
        } catch (InterruptedException e) {
            throw new RuntimeException("waiting thread interrupted", e);
        }
    }
    return result;
}

From source file:com.scvngr.levelup.core.test.SupportLoaderTestCase.java

/**
 * Runs a Loader synchronously and returns the result of the load. The loader will be started,
 * stopped, and destroyed by this method so it cannot be reused.
 *
 * @param loader The loader to run synchronously
 * @return The result from the loader//  w  w w .j a  v  a  2s.  c  o  m
 */
public <T> T getLoaderResultSynchronously(final Loader<T> loader) {
    // The test thread blocks on this queue until the loader puts its result in
    final ArrayBlockingQueue<T> queue = new ArrayBlockingQueue<T>(1);
    final CountDownLatch latch = new CountDownLatch(1);

    // This callback runs on the "main" thread and unblocks the test thread
    // when it puts the result into the blocking queue
    final OnLoadCompleteListener<T> listener = new OnLoadCompleteListener<T>() {
        @Override
        public void onLoadComplete(final Loader<T> completedLoader, final T data) {
            // Shut the loader down
            completedLoader.unregisterListener(this);
            completedLoader.stopLoading();
            completedLoader.reset();

            // Store the result, unblocking the test thread
            if (null != data) {
                queue.add(data);
            }
            latch.countDown();
        }
    };

    // This handler runs on the "main" thread of the process since AsyncTask
    // is documented as needing to run on the main thread and many Loaders use
    // AsyncTask
    final Handler mainThreadHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(final Message msg) {
            loader.registerListener(0, listener);
            loader.startLoading();
        }
    };

    // Ask the main thread to start the loading process
    mainThreadHandler.sendEmptyMessage(0);

    // Block on the queue waiting for the result of the load to be inserted
    T result;
    while (true) {
        try {
            latch.await();
            result = queue.peek();
            break;
        } catch (final InterruptedException e) {
            throw new RuntimeException("waiting thread interrupted", e);
        }
    }

    return result;
}

From source file:org.kchine.r.server.RListener.java

public static String[] clusterApply(final String cl, final String varName, final String functionName,
        final String ato, final String asynch) {
    new Thread(new Runnable() {
        public void run() {
            try {

                Cluster cluster = _clustersHash.get(cl);

                if (cluster == null) {
                    new Thread(new Runnable() {
                        public void run() {
                            try {
                                DirectJNI.getInstance().getRServices()
                                        .consoleSubmit(convertToPrintCommand("Invalid cluster"));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }// www  . j  a v  a  2 s.c om
                        }
                    }).start();

                }

                RObject v = DirectJNI.getInstance().getRServices().getObject(varName);
                RObject vtemp = null;
                if (v.getClass() == RMatrix.class) {
                    vtemp = ((RMatrix) v).getValue();
                } else if (v.getClass() == RArray.class) {
                    vtemp = ((RArray) v).getValue();
                } else {
                    vtemp = v;
                }

                final RObject var = vtemp;

                final VWrapper vwrapper = new VWrapper() {
                    public int getSize() {
                        if (var.getClass() == RNumeric.class) {
                            return ((RNumeric) var).getValue().length;
                        } else if (var.getClass() == RInteger.class) {
                            return ((RInteger) var).getValue().length;
                        } else if (var.getClass() == RChar.class) {
                            return ((RChar) var).getValue().length;
                        } else if (var.getClass() == RLogical.class) {
                            return ((RLogical) var).getValue().length;
                        } else if (var.getClass() == RComplex.class) {
                            return ((RComplex) var).getReal().length;
                        } else if (var.getClass() == RList.class) {
                            return ((RList) var).getValue().length;
                        }
                        return 0;
                    }

                    public RObject getElementAt(int i) {
                        if (var.getClass() == RNumeric.class) {
                            return new RNumeric(((RNumeric) var).getValue()[i]);
                        } else if (var.getClass() == RInteger.class) {
                            return new RInteger(((RInteger) var).getValue()[i]);
                        } else if (var.getClass() == RChar.class) {
                            return new RChar(((RChar) var).getValue()[i]);
                        } else if (var.getClass() == RLogical.class) {
                            return new RLogical(((RLogical) var).getValue()[i]);
                        } else if (var.getClass() == RComplex.class) {
                            return new RComplex(new double[] { ((RComplex) var).getReal()[i] },
                                    new double[] { ((RComplex) var).getImaginary()[i] },
                                    ((RComplex) var).getIndexNA() != null
                                            ? new int[] { ((RComplex) var).getIndexNA()[i] }
                                            : null,
                                    ((RComplex) var).getNames() != null
                                            ? new String[] { ((RComplex) var).getNames()[i] }
                                            : null);
                        }

                        else if (var.getClass() == RList.class) {
                            return (RObject) ((RList) var).getValue()[i];
                        }
                        return null;
                    }

                    public Object gatherResults(RObject[] f) {

                        if (var.getClass() == RList.class) {
                            return f;
                        } else {
                            Class<?> resultClass = f[0].getClass();
                            RObject result = null;
                            if (resultClass == RNumeric.class) {
                                double[] t = new double[f.length];
                                for (int i = 0; i < f.length; ++i)
                                    t[i] = ((RNumeric) f[i]).getValue()[0];
                                result = new RNumeric(t);
                            } else if (resultClass == RInteger.class) {
                                int[] t = new int[f.length];
                                for (int i = 0; i < f.length; ++i)
                                    t[i] = ((RInteger) f[i]).getValue()[0];
                                result = new RInteger(t);
                            } else if (resultClass == RChar.class) {
                                String[] t = new String[f.length];
                                for (int i = 0; i < f.length; ++i)
                                    t[i] = ((RChar) f[i]).getValue()[0];
                                result = new RChar(t);
                            } else if (resultClass == RLogical.class) {
                                boolean[] t = new boolean[f.length];
                                for (int i = 0; i < f.length; ++i)
                                    t[i] = ((RLogical) f[i]).getValue()[0];
                                result = new RLogical(t);
                            } else if (resultClass == RComplex.class) {
                                double[] real = new double[f.length];
                                double[] im = new double[f.length];

                                for (int i = 0; i < f.length; ++i) {
                                    real[i] = ((RComplex) f[i]).getReal()[0];
                                    im[i] = ((RComplex) f[i]).getImaginary()[0];
                                }

                                result = new RComplex(real, im, null, null);
                            } else {
                                throw new RuntimeException(
                                        "Can't Handle this result type :" + resultClass.getName());
                            }
                            return result;
                        }

                    }
                };

                if (vwrapper.getSize() == 0) {

                    new Thread(new Runnable() {
                        public void run() {
                            try {
                                DirectJNI.getInstance().getRServices()
                                        .consoleSubmit(convertToPrintCommand("0 elements in data"));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();

                }

                Vector<RServices> workers = cluster.getWorkers();

                final ArrayBlockingQueue<Integer> indexesQueue = new ArrayBlockingQueue<Integer>(
                        vwrapper.getSize());
                for (int i = 0; i < vwrapper.getSize(); ++i)
                    indexesQueue.add(i);

                final ArrayBlockingQueue<RServices> workersQueue = new ArrayBlockingQueue<RServices>(
                        workers.size());
                for (int i = 0; i < workers.size(); ++i)
                    workersQueue.add(workers.elementAt(i));

                final RObject[] result = new RObject[vwrapper.getSize()];

                for (int i = 0; i < workers.size(); ++i) {
                    new Thread(new Runnable() {
                        public void run() {
                            RServices r = workersQueue.poll();
                            while (indexesQueue.size() > 0) {
                                Integer idx = indexesQueue.poll();
                                if (idx != null) {
                                    try {
                                        result[idx] = r.call(functionName, vwrapper.getElementAt(idx));
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        result[idx] = nullObject;
                                    }
                                }
                            }
                        }
                    }).start();
                }

                while (true) {
                    int count = 0;
                    for (int i = 0; i < result.length; ++i)
                        if (result[i] != null)
                            ++count;
                    if (count == result.length)
                        break;
                    Thread.sleep(100);
                }

                Object reconstituedObject = vwrapper.gatherResults(result);
                if (v.getClass() == RMatrix.class) {
                    ((RArray) v).setValue((RVector) reconstituedObject);
                } else if (v.getClass() == RArray.class) {
                    ((RArray) v).setValue((RVector) reconstituedObject);
                } else if (v.getClass() == RList.class) {
                    ((RList) v).setValue((RObject[]) reconstituedObject);
                } else {
                    v = (RObject) reconstituedObject;
                }

                final RObject final_v = v;
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            DirectJNI.getInstance().getRServices().putAndAssign(final_v,
                                    (ato.equals("") ? functionName + "_" + varName : ato));
                            DirectJNI.getInstance().getRServices().consoleSubmit(
                                    convertToPrintCommand("Cluster Apply result assigned to R variable "
                                            + (ato.equals("") ? functionName + "_" + varName : ato) + "\n"));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }).start();

    return new String[] { "OK", convertToPrintCommand("Cluster Apply Submitted in background..") };
}

From source file:it.unimi.di.big.mg4j.document.WikipediaDocumentSequence.java

@Override
public DocumentIterator iterator() throws IOException {
    final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    saxParserFactory.setNamespaceAware(true);
    final MutableString nameSpaceAccumulator = new MutableString();
    final ObjectOpenHashSet<MutableString> nameSpacesAccumulator = new ObjectOpenHashSet<MutableString>();
    final ArrayBlockingQueue<DocumentFactory> freeFactories = new ArrayBlockingQueue<DocumentFactory>(16);
    for (int i = freeFactories.remainingCapacity(); i-- != 0;)
        freeFactories.add(this.factory.copy());
    final ArrayBlockingQueue<DocumentAndFactory> readyDocumentsAndFactories = new ArrayBlockingQueue<DocumentAndFactory>(
            freeFactories.size());//from   ww  w  .  j ava2 s  . c  om

    final SAXParser parser;
    try {
        parser = saxParserFactory.newSAXParser();
    } catch (Exception e) {
        throw new RuntimeException(e.getMessage(), e);
    }
    final DefaultHandler handler = new DefaultHandler() {
        private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        private boolean inText;
        private boolean inTitle;
        private boolean inId;
        private boolean inTimestamp;
        private boolean inNamespaceDef;
        private boolean redirect;
        private MutableString text = new MutableString();
        private MutableString title = new MutableString();
        private MutableString id = new MutableString();
        private MutableString timestamp = new MutableString();
        private final Reference2ObjectMap<Enum<?>, Object> metadata = new Reference2ObjectOpenHashMap<Enum<?>, Object>();
        {
            metadata.put(PropertyBasedDocumentFactory.MetadataKeys.ENCODING, "UTF-8");
            metadata.put(MetadataKeys.REDIRECT, redirectAnchors);
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            if ("page".equals(localName)) {
                redirect = inText = inTitle = inId = inTimestamp = false;
                text.length(0);
                title.length(0);
                id.length(0);
                timestamp.length(0);
            } else if ("text".equals(localName))
                inText = true;
            else if ("title".equals(localName) && title.length() == 0)
                inTitle = true; // We catch only the first id/title elements.
            else if ("id".equals(localName) && id.length() == 0)
                inId = true;
            else if ("timestamp".equals(localName) && timestamp.length() == 0)
                inTimestamp = true;
            else if ("redirect".equals(localName)) {
                redirect = true;
                if (attributes.getValue("title") != null)
                    // Accumulate the title of the page as virtual text of the redirect page.
                    synchronized (redirectAnchors) {
                        final String link = Encoder.encodeTitleToUrl(attributes.getValue("title"), true);
                        redirectAnchors.add(
                                new AnchorExtractor.Anchor(new MutableString(baseURL.length() + link.length())
                                        .append(baseURL).append(link), title.copy()));
                    }
            } else if ("namespace".equals(localName)) {
                // Found a new namespace
                inNamespaceDef = true;
                nameSpaceAccumulator.length(0);
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if ("namespace".equals(localName)) { // Collecting a namespace
                if (nameSpaceAccumulator.length() != 0)
                    nameSpacesAccumulator.add(nameSpaceAccumulator.copy().toLowerCase());
                return;
            }

            if ("namespaces".equals(localName)) { // All namespaces collected
                nameSpaces = ImmutableSet.copyOf(nameSpacesAccumulator);
                return;
            }

            if (!redirect) {
                if ("title".equals(localName)) {
                    // Set basic metadata for the page
                    metadata.put(PropertyBasedDocumentFactory.MetadataKeys.TITLE, title.copy());
                    String link = Encoder.encodeTitleToUrl(title.toString(), true);
                    metadata.put(PropertyBasedDocumentFactory.MetadataKeys.URI,
                            new MutableString(baseURL.length() + link.length()).append(baseURL).append(link));
                    inTitle = false;
                } else if ("id".equals(localName)) {
                    metadata.put(MetadataKeys.ID, Long.valueOf(id.toString()));
                    inId = false;
                } else if ("timestamp".equals(localName)) {
                    try {
                        metadata.put(MetadataKeys.LASTEDIT, dateFormat.parse(timestamp.toString()));
                    } catch (ParseException e) {
                        throw new RuntimeException(e.getMessage(), e);
                    }
                    inTimestamp = false;
                } else if ("text".equals(localName)) {
                    inText = false;
                    if (!keepNamespaced) {
                        // Namespaces are case-insensitive and language-dependent
                        final int pos = title.indexOf(':');
                        if (pos != -1 && nameSpaces.contains(title.substring(0, pos).toLowerCase()))
                            return;
                    }
                    try {
                        final MutableString html = new MutableString();
                        DocumentFactory freeFactory;
                        try {
                            freeFactory = freeFactories.take();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e.getMessage(), e);
                        }
                        if (parseText) {
                            if (DISAMBIGUATION.search(text) != -1) { // It's a disambiguation page.
                                /* Roi's hack: duplicate links using the page title, so the generic name will end up as anchor text. */
                                final MutableString newLinks = new MutableString();
                                for (int start = 0, end; (start = BRACKETS_OPEN.search(text,
                                        start)) != -1; start = end) {
                                    end = start;
                                    final int endOfLink = text.indexOfAnyOf(END_OF_DISAMBIGUATION_LINK, start);
                                    // Note that we don't escape title because we are working at the Wikipedia raw text level.
                                    if (endOfLink != -1) {
                                        newLinks.append(text.array(), start, endOfLink - start).append('|')
                                                .append(title).append("]]\n");
                                        end = endOfLink;
                                    }
                                    end++;
                                }

                                text.append(newLinks);
                            }
                            // We separate categories by OXOXO, so we don't get overflowing phrases.
                            final MutableString category = new MutableString();
                            for (int start = 0, end; (start = CATEGORY_START.search(text,
                                    start)) != -1; start = end) {
                                end = BRACKETS_CLOSED.search(text, start += CATEGORY_START.length());
                                if (end != -1)
                                    category.append(text.subSequence(start, end)).append(" OXOXO ");
                                else
                                    break;
                            }
                            metadata.put(MetadataKeys.CATEGORY, category);

                            // Heuristics to get the first paragraph
                            metadata.put(MetadataKeys.FIRSTPAR, new MutableString());
                            String plainText = wikiModel.render(new PlainTextConverter(true), text.toString());
                            for (int start = 0; start < plainText.length(); start++) {
                                //System.err.println("Examining " + plainText.charAt( start )  );
                                if (Character.isWhitespace(plainText.charAt(start)))
                                    continue;
                                if (plainText.charAt(start) == '{') {
                                    //System.err.print( "Braces " + start + " text: \"" + plainText.subSequence( start, start + 10 )  + "\" -> " );
                                    start = BRACES_CLOSED.search(plainText, start);
                                    //System.err.println( start + " text: \"" + plainText.subSequence( start, start + 10 ) + "\"" );
                                    if (start == -1)
                                        break;
                                    start++;
                                } else if (plainText.charAt(start) == '[') {
                                    start = BRACKETS_CLOSED.search(plainText, start);
                                    if (start == -1)
                                        break;
                                    start++;
                                } else {
                                    final int end = plainText.indexOf('\n', start);
                                    if (end != -1)
                                        metadata.put(MetadataKeys.FIRSTPAR,
                                                new MutableString(plainText.substring(start, end)));
                                    break;
                                }
                            }

                            try {
                                wikiModel.render(new HTMLConverter(), text.toString(), html, false, true);
                                final Map<String, String> categories = wikiModel.getCategories();
                                // Put back category links in the page (they have been parsed by bliki and to not appear anymore in the HTML rendering)
                                for (Entry<String, String> entry : categories.entrySet()) {
                                    final String key = entry.getKey();
                                    final String value = entry.getValue().trim();
                                    if (value.length() != 0) // There are empty such things
                                        html.append("\n<a href=\"").append(baseURL).append("Category:")
                                                .append(Encoder.encodeTitleToUrl(key, true)).append("\">")
                                                .append(HtmlEscapers.htmlEscaper().escape(key))
                                                .append("</a>\n");
                                }
                            } catch (Exception e) {
                                LOGGER.error("Unexpected exception while parsing " + title, e);
                            }
                        }
                        readyDocumentsAndFactories.put(new DocumentAndFactory(
                                freeFactory.getDocument(IOUtils.toInputStream(html, Charsets.UTF_8),
                                        new Reference2ObjectOpenHashMap<Enum<?>, Object>(metadata)),
                                freeFactory));
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e.getMessage(), e);
                    } catch (IOException e) {
                        throw new RuntimeException(e.getMessage(), e);
                    }
                }
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if (inText && parseText)
                text.append(ch, start, length);
            if (inTitle)
                title.append(ch, start, length);
            if (inId)
                id.append(ch, start, length);
            if (inTimestamp)
                timestamp.append(ch, start, length);
            if (inNamespaceDef) {
                nameSpaceAccumulator.append(ch, start, length);
                inNamespaceDef = false; // Dirty, but it works
            }
        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            if (inText && parseText)
                text.append(ch, start, length);
            if (inTitle)
                title.append(ch, start, length);
        }
    };

    final Thread parsingThread = new Thread() {
        public void run() {
            try {
                InputStream in = new FileInputStream(wikipediaXmlDump);
                if (bzipped)
                    in = new BZip2CompressorInputStream(in);
                parser.parse(
                        new InputSource(new InputStreamReader(new FastBufferedInputStream(in), Charsets.UTF_8)),
                        handler);
                readyDocumentsAndFactories.put(END);
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    };

    parsingThread.start();

    return new AbstractDocumentIterator() {
        private DocumentFactory lastFactory;

        @Override
        public Document nextDocument() throws IOException {
            try {
                final DocumentAndFactory documentAndFactory = readyDocumentsAndFactories.take();
                if (lastFactory != null)
                    freeFactories.put(lastFactory);
                if (documentAndFactory == END)
                    return null;
                lastFactory = documentAndFactory.factory;
                return documentAndFactory.document;
            } catch (InterruptedException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    };
}