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 javax.naming.directory.SearchControls;
29import javax.naming.event.*;
30
31/**
32 * This class holds the information in an event registration/deregistration
33 * request. This includes the name, filter, search controls and
34 * the different interfaces that the listener implements. This last piece
35 * of information determines which event(s) the listener is interested in.
36 *<p>
37 * It overrides equals() and hashCode() to use all these pieces of
38 * information so that it can be used correctly in a hashtable.
39 *
40 * @author Rosanna Lee
41 */
42final class NotifierArgs {
43    static final int ADDED_MASK = 0x1;
44    static final int REMOVED_MASK = 0x2;
45    static final int CHANGED_MASK = 0x4;
46    static final int RENAMED_MASK = 0x8;
47
48    // these fields are package private; used by NamingEventNotifier
49    String name;
50    String filter;
51    SearchControls controls;
52    int mask;
53
54    // package private
55    NotifierArgs(String name, int scope, NamingListener l) {
56        this(name, "(objectclass=*)", null, l);
57
58        // if scope is not default, create search ctl and set it
59        if (scope != EventContext.ONELEVEL_SCOPE) {
60            controls = new SearchControls();
61            controls.setSearchScope(scope);
62        }
63    }
64
65    // package private
66    NotifierArgs(String name, String filter, SearchControls ctls,
67        NamingListener l) {
68        this.name = name;
69        this.filter = filter;
70        this.controls = ctls;
71
72        if (l instanceof NamespaceChangeListener) {
73            mask |= ADDED_MASK|REMOVED_MASK|RENAMED_MASK;
74        }
75        if (l instanceof ObjectChangeListener) {
76            mask |= CHANGED_MASK;
77        }
78    }
79
80    // checks name, filter, controls
81    public boolean equals(Object obj) {
82        if (obj instanceof NotifierArgs) {
83            NotifierArgs target = (NotifierArgs)obj;
84            return mask == target.mask &&
85                name.equals(target.name) && filter.equals(target.filter) &&
86                checkControls(target.controls);
87        }
88        return false;
89    }
90
91    private boolean checkControls(SearchControls ctls) {
92        if ((controls == null || ctls == null)) {
93            return ctls == controls;
94        }
95        // ctls are nonempty
96
97        return (controls.getSearchScope() == ctls.getSearchScope()) &&
98            (controls.getTimeLimit() == ctls.getTimeLimit()) &&
99            (controls.getDerefLinkFlag() == ctls.getDerefLinkFlag()) &&
100            (controls.getReturningObjFlag() == ctls.getReturningObjFlag()) &&
101            (controls.getCountLimit() == ctls.getCountLimit()) &&
102            checkStringArrays(controls.getReturningAttributes(),
103                ctls.getReturningAttributes());
104    }
105
106    private static boolean checkStringArrays(String[] s1, String[] s2) {
107        if ((s1 == null) || (s2 == null)) {
108            return s1 == s2;
109        }
110
111        // both are nonnull
112        if (s1.length != s2.length) {
113            return false;
114        }
115
116        for (int i = 0; i < s1.length; i++) {
117            if (!s1[i].equals(s2[i])) {
118                return false;
119            }
120        }
121        return true;
122    }
123
124    // save from having to recalculate each time
125    private int sum = -1;
126    public int hashCode() {
127        if (sum == -1)
128            sum = mask + name.hashCode() + filter.hashCode() + controlsCode();
129        return sum;
130    }
131
132    // used in calculating hash code
133    private int controlsCode() {
134        if (controls == null) return 0;
135
136        int total = controls.getTimeLimit() + (int)controls.getCountLimit() +
137            (controls.getDerefLinkFlag() ? 1 : 0) +
138            (controls.getReturningObjFlag() ? 1 : 0);
139
140        String[] attrs = controls.getReturningAttributes();
141        if (attrs != null) {
142            for (int i = 0; i < attrs.length; i++) {
143                total += attrs[i].hashCode();
144            }
145        }
146
147        return total;
148    }
149}
150