View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  
47  package org.exolab.castor.dsml;
48  
49  
50  import java.io.Serializable;
51  import java.util.Hashtable;
52  import java.util.Enumeration;
53  import java.util.StringTokenizer;
54  import org.xml.sax.DocumentHandler;
55  import org.xml.sax.AttributeList;
56  import org.xml.sax.SAXException;
57  import org.xml.sax.HandlerBase;
58  import org.xml.sax.helpers.AttributeListImpl;
59  import org.castor.core.util.Messages;
60  
61  
62  /**
63   *
64   *
65   * @author <a href="mailto:arkin@intalio.com">Assaf Arkin</a>
66   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
67   */
68  public class ImportDescriptor extends HandlerBase implements Serializable {
69      /** SerialVersionUID. */
70      private static final long serialVersionUID = 197365948293655041L;
71  
72      public static class Policy {
73          /** Under the <code>DeleteEmpty</code> policy, entries without attributes in the
74           *  DSML are deleted from the Ldap. */
75          public static final int DELETE_EMPTY = 0x01;
76          /** Under the <code>ReplaceAttr</code> policy, attributes in the Ldap that are not
77           *  specified in the DSML are deleted. */
78          public static final int REPLACE_ATTRIBUTE = 0x02;
79          /** Under the <code>RefreshOnly</code> policy, DSML entries that do not already
80           *  exist in the Ldap are not created. */
81          public static final int REFRESH_ONLY = 0x04;
82          /** Under the <code>NewAttrOnly</code> policy, new attributes are created according
83           *  to the DSML, but attributes that already have a value in the ldap are not updated. */
84          public static final int NEW_ATTRIBUTE_ONLY = 0x08;
85          /** Under the <code>UpdateOnly</code> policy, DSML attributes that do not already
86           *  exist in the Ldap are not created. */
87          public static final int UPDATE_ONLY = 0x10;
88          /** Under the <code>DefaultPolicy</code> policy. */
89          public static final int DEFAULT_POLICY = 0x00;
90      }
91  
92      static class Names {
93          static class Element {
94              public static final String POLICIES = "import-policies";
95              public static final String POLICY = "import-policy";
96          }
97  
98          static class Attribute {
99              public static final String DN = "dn";
100             public static final String DELETE_EMPTY = "delete-empty";
101             public static final String REPLACE_ATTRIBUTE = "replace-attr";
102             public static final String REFRESH_ONLY = "refresh-only";
103             public static final String UPDATE_ONLY = "update-only";
104             public static final String NEW_ATTRIBUTE_ONLY = "new-attr-only";
105         }
106     }
107     
108     private Hashtable _policies = new Hashtable();
109 
110     private boolean _insideRoot;
111 
112     public ImportDescriptor() {
113     }
114 
115     public Enumeration listDNs() {
116         return _policies.keys();
117     }
118 
119     public void addPolicy(final String name, final int policy) {
120         _policies.put(name, new Integer(policy));
121     }
122 
123     public int getDirectPolicy(final String name) {
124         Integer policy = (Integer) _policies.get(name);
125         if (policy != null) { return policy.intValue(); }
126         return Policy.DEFAULT_POLICY;
127     }
128 
129     public int getPolicy(String name) {
130         DN       dn;
131         Integer  policy;
132         int      i;
133         
134         policy = (Integer) _policies.get(name);
135         if (policy != null) { return policy.intValue(); }
136         dn = new DN( name );
137         for (i = 1; i < dn.size(); ++i) {
138             name = dn.suffix(i);
139             policy = (Integer) _policies.get(name);
140             if (policy != null) { return policy.intValue(); }
141         }
142         return Policy.DEFAULT_POLICY;
143     }
144 
145     public void produce(final DocumentHandler docHandler) throws SAXException {
146         AttributeListImpl attrList;
147         int policy;
148         Enumeration enumeration;
149         String name;
150 
151         attrList = new AttributeListImpl();
152         docHandler.startElement(XML.Namespace.ROOT, attrList);
153         attrList = new AttributeListImpl();
154         docHandler.startElement(Names.Element.POLICIES, attrList);
155 
156         enumeration = listDNs();
157         while (enumeration.hasMoreElements()) {
158             name = (String) enumeration.nextElement();
159             policy = getDirectPolicy(name);
160             attrList = new AttributeListImpl();
161             attrList.addAttribute(Names.Attribute.DN, "ID", name);
162             if ((policy & Policy.DELETE_EMPTY) != 0) {
163                 attrList.addAttribute(Names.Attribute.DELETE_EMPTY, null, "true");
164             }
165             if ((policy & Policy.REPLACE_ATTRIBUTE) != 0) {
166                 attrList.addAttribute(Names.Attribute.REPLACE_ATTRIBUTE, null, "true");
167             }
168             if ((policy & Policy.REFRESH_ONLY) != 0) {
169                 attrList.addAttribute(Names.Attribute.REFRESH_ONLY, null, "true");
170             }
171             if ((policy & Policy.UPDATE_ONLY) != 0) {
172                 attrList.addAttribute(Names.Attribute.UPDATE_ONLY, null, "true");
173             }
174             if ((policy & Policy.NEW_ATTRIBUTE_ONLY) != 0) {
175                 attrList.addAttribute(Names.Attribute.NEW_ATTRIBUTE_ONLY, null, "true");
176             }
177             docHandler.startElement(Names.Element.POLICY, attrList);
178             docHandler.endElement(Names.Element.POLICY);
179         }
180 
181         docHandler.endElement(Names.Element.POLICIES);
182         docHandler.endElement(XML.Namespace.ROOT);
183     }
184 
185 
186     public void startElement(final String tagName, final AttributeList attr) throws SAXException {
187         String dn;
188         int policy;
189 
190         if (tagName.equals(XML.Namespace.ROOT)) {
191             // Flag when entering (and leaving) the root element.
192             if (_insideRoot) {
193                 throw new SAXException(Messages.format(
194                         "dsml.elementNested", XML.Namespace.ROOT));
195             }
196             _insideRoot = true;
197         } else {
198             if (!_insideRoot) {
199                 throw new SAXException(Messages.format(
200                         "dsml.expectingOpeningTag", XML.Namespace.ROOT, tagName));
201             }
202 
203             if (tagName.equals(Names.Element.POLICIES)) {
204                 // Nothing to do at level of top element
205             } else if (tagName.equals(Names.Element.POLICY)) {
206                 dn = attr.getValue(Names.Attribute.DN);
207                 if (dn == null) {
208                     throw new SAXException(Messages.format("dsml.missingAttribute",
209                             Names.Element.POLICY, Names.Attribute.DN));
210                 }
211                 policy = 0;
212                 if ("true".equals(attr.getValue(Names.Attribute.DELETE_EMPTY))) {
213                     policy = policy | Policy.DELETE_EMPTY;
214                 }
215                 if ("true".equals(attr.getValue(Names.Attribute.REFRESH_ONLY))) {
216                     policy = policy | Policy.REFRESH_ONLY;
217                 }
218                 if ("true".equals(attr.getValue(Names.Attribute.REPLACE_ATTRIBUTE))) {
219                     policy = policy | Policy.REPLACE_ATTRIBUTE;
220                 }
221                 if ("true".equals(attr.getValue(Names.Attribute.NEW_ATTRIBUTE_ONLY))) {
222                     policy = policy | Policy.NEW_ATTRIBUTE_ONLY;
223                 }
224                 if ("true".equals(attr.getValue(Names.Attribute.UPDATE_ONLY))) {
225                     policy = policy | Policy.UPDATE_ONLY;
226                 }
227                 addPolicy(dn, policy);
228             } else {
229                 throw new SAXException(Messages.format(
230                         "dsml.expectingOpeningTag", Names.Element.POLICIES, tagName));
231             }
232         }
233     }
234 
235     public void endElement(final String tagName) throws SAXException {
236         if (tagName.equals(XML.Namespace.ROOT)) {
237             if (_insideRoot) {
238                 _insideRoot = false;
239             } else {
240                 throw new SAXException(Messages.format("dsml.closingOutsideRoot", tagName));
241             }
242         } else {
243             if (!_insideRoot) {
244                 throw new SAXException(Messages.format("dsml.closingOutsideRoot", tagName));
245             }
246             if (tagName.equals(Names.Element.POLICIES)) {
247                 // Nothing to do here
248             } else if (tagName.equals(Names.Element.POLICY)) {
249                 // Nothing to do here
250             } else {
251                 throw new SAXException(Messages.format("dsml.expectingClosingTag",
252                         Names.Element.POLICIES, tagName));
253             }
254         }
255     }
256 
257     static class DN {
258         private String[] _names;
259 
260         DN(final String name) {
261             StringTokenizer token;
262             int i;
263 
264             token = new StringTokenizer(name, ", ");
265             _names = new String[token.countTokens()];
266             for (i = 0; token.hasMoreTokens(); ++i) {
267                 _names[ i ] = token.nextToken();
268             }
269         }
270 
271         int size() {
272             return _names.length;
273         }
274 
275         String suffix(int index) {
276             StringBuffer name;
277 
278             name = new StringBuffer(_names[index]);
279             for (++index; index < _names.length; ++index) {
280                 name.append(',').append(_names[index]);
281             }
282             return name.toString();
283         }
284     }
285 }