1/*
2 * Copyright (c) 1999, 2011, 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
26package com.sun.jndi.ldap;
27
28import java.io.IOException;
29import java.util.concurrent.BlockingQueue;
30import java.util.concurrent.LinkedBlockingQueue;
31import javax.naming.CommunicationException;
32
33final class LdapRequest {
34
35    LdapRequest next;   // Set/read in synchronized Connection methods
36    int msgId;          // read-only
37
38    private int gotten = 0;
39    private BlockingQueue<BerDecoder> replies;
40    private int highWatermark = -1;
41    private boolean cancelled = false;
42    private boolean pauseAfterReceipt = false;
43    private boolean completed = false;
44
45    LdapRequest(int msgId, boolean pause) {
46        this(msgId, pause, -1);
47    }
48
49    LdapRequest(int msgId, boolean pause, int replyQueueCapacity) {
50        this.msgId = msgId;
51        this.pauseAfterReceipt = pause;
52        if (replyQueueCapacity == -1) {
53            this.replies = new LinkedBlockingQueue<BerDecoder>();
54        } else {
55            this.replies =
56                new LinkedBlockingQueue<BerDecoder>(replyQueueCapacity);
57            highWatermark = (replyQueueCapacity * 80) / 100; // 80% capacity
58        }
59    }
60
61    synchronized void cancel() {
62        cancelled = true;
63
64        // Unblock reader of pending request
65        // Should only ever have at most one waiter
66        notify();
67    }
68
69    synchronized boolean addReplyBer(BerDecoder ber) {
70        if (cancelled) {
71            return false;
72        }
73
74        // Add a new reply to the queue of unprocessed replies.
75        try {
76            replies.put(ber);
77        } catch (InterruptedException e) {
78            // ignore
79        }
80
81        // peek at the BER buffer to check if it is a SearchResultDone PDU
82        try {
83            ber.parseSeq(null);
84            ber.parseInt();
85            completed = (ber.peekByte() == LdapClient.LDAP_REP_RESULT);
86        } catch (IOException e) {
87            // ignore
88        }
89        ber.reset();
90
91        notify(); // notify anyone waiting for reply
92        /*
93         * If a queue capacity has been set then trigger a pause when the
94         * queue has filled to 80% capacity. Later, when the queue has drained
95         * then the reader gets unpaused.
96         */
97        if (highWatermark != -1 && replies.size() >= highWatermark) {
98            return true; // trigger the pause
99        }
100        return pauseAfterReceipt;
101    }
102
103    synchronized BerDecoder getReplyBer() throws CommunicationException {
104        if (cancelled) {
105            throw new CommunicationException("Request: " + msgId +
106                " cancelled");
107        }
108
109        /*
110         * Remove a reply if the queue is not empty.
111         * poll returns null if queue is empty.
112         */
113        BerDecoder reply = replies.poll();
114        return reply;
115    }
116
117    synchronized boolean hasSearchCompleted() {
118        return completed;
119    }
120}
121