jdk/src/share/classes/sun/security/pkcs11/TemplateManager.java
author ohair
Tue, 25 May 2010 15:58:33 -0700 (2010-05-25)
changeset 5506 202f599c92aa
parent 2 90ce3da70b43
permissions -rw-r--r--
6943119: Rebrand source copyright notices Reviewed-by: darcy, weijun
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
     2
 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
    23
 * questions.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package sun.security.pkcs11;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.util.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.util.concurrent.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import sun.security.pkcs11.wrapper.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
 * TemplateManager class.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
 * Not all PKCS#11 tokens are created equal. One token may require that one
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
 * value is specified when creating a certain type of object. Another token
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
 * may require a different value. Yet another token may only work if the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
 * attribute is not specified at all.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 * In order to allow an application to work unmodified with all those
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * different tokens, the SunPKCS11 provider makes the attributes that are
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 * specified and their value configurable. Hence, only the SunPKCS11
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 * configuration file has to be tweaked at deployment time to allow all
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 * existing applications to be used.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 * The template manager is responsible for reading the attribute configuration
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 * information and to make it available to the various internal components
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
 * of the SunPKCS11 provider.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
 * @author  Andreas Sterbenz
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
 * @since   1.5
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
final class TemplateManager {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
    private final static boolean DEBUG = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
    // constant for any operation (either O_IMPORT or O_GENERATE)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
    final static String O_ANY      = "*";
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
    // constant for operation create ("importing" existing key material)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
    final static String O_IMPORT   = "import";
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    // constant for operation generate (generating new key material)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
    final static String O_GENERATE = "generate";
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    private static class KeyAndTemplate {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
        final TemplateKey key;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
        final Template template;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
        KeyAndTemplate(TemplateKey key, Template template) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
            this.key = key;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
            this.template = template;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
    // primitive templates contains the individual template configuration
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
    // entries from the configuration file
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
    private final List<KeyAndTemplate> primitiveTemplates;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
    // composite templates is a cache of the exact configuration template for
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
    // each specific TemplateKey (no wildcards). the entries are created
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
    // on demand during first use by compositing all applicable
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
    // primitive template entries. the result is then stored in this map
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
    // for performance
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
    private final Map<TemplateKey,Template> compositeTemplates;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
    TemplateManager() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
        primitiveTemplates = new ArrayList<KeyAndTemplate>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
        compositeTemplates = new ConcurrentHashMap<TemplateKey,Template>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
    // add a template. Called by Config.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
    void addTemplate(String op, long objectClass, long keyAlgorithm,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
            CK_ATTRIBUTE[] attrs) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
        TemplateKey key = new TemplateKey(op, objectClass, keyAlgorithm);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
        Template template = new Template(attrs);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
        if (DEBUG) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
            System.out.println("Adding " + key + " -> " + template);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
        primitiveTemplates.add(new KeyAndTemplate(key, template));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
    private Template getTemplate(TemplateKey key) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
        Template template = compositeTemplates.get(key);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
        if (template == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
            template = buildCompositeTemplate(key);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
            compositeTemplates.put(key, template);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
        return template;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
    // Get the attributes for the requested op and combine them with attrs.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
    // This is the method called by the implementation to obtain the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
    // attributes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
    CK_ATTRIBUTE[] getAttributes(String op, long type, long alg,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
            CK_ATTRIBUTE[] attrs) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
        TemplateKey key = new TemplateKey(op, type, alg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
        Template template = getTemplate(key);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
        CK_ATTRIBUTE[] newAttrs = template.getAttributes(attrs);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
        if (DEBUG) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
            System.out.println(key + " -> " + Arrays.asList(newAttrs));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
        return newAttrs;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
    // build a composite template for the given key
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
    private Template buildCompositeTemplate(TemplateKey key) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
        Template comp = new Template();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        // iterate through primitive templates and add all that apply
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
        for (KeyAndTemplate entry : primitiveTemplates) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
            if (entry.key.appliesTo(key)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
                comp.add(entry.template);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
        return comp;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
     * Nested class representing a template identifier.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
    private static final class TemplateKey {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        final String operation;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
        final long keyType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
        final long keyAlgorithm;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
        TemplateKey(String operation, long keyType, long keyAlgorithm) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
            this.operation = operation;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
            this.keyType = keyType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
            this.keyAlgorithm = keyAlgorithm;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
        public boolean equals(Object obj) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
            if (this == obj) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
                return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
            if (obj instanceof TemplateKey == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
                return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
            TemplateKey other = (TemplateKey)obj;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
            boolean match = this.operation.equals(other.operation)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
                        && (this.keyType == other.keyType)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
                        && (this.keyAlgorithm == other.keyAlgorithm);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
            return match;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
        public int hashCode() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
            return operation.hashCode() + (int)keyType + (int)keyAlgorithm;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
        boolean appliesTo(TemplateKey key) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
            if (operation.equals(O_ANY) || operation.equals(key.operation)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
                if ((keyType == PCKO_ANY) || (keyType == key.keyType)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
                    if ((keyAlgorithm == PCKK_ANY)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
                                || (keyAlgorithm == key.keyAlgorithm)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
                        return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
            return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
        public String toString() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
            return "(" + operation + ","
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
                + Functions.getObjectClassName(keyType)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
                + "," + Functions.getKeyName(keyAlgorithm) + ")";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
     * Nested class representing template attributes.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
    private static final class Template {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
        private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
        private CK_ATTRIBUTE[] attributes;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
        Template() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
            attributes = A0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
        Template(CK_ATTRIBUTE[] attributes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
            this.attributes = attributes;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
        void add(Template template) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
            attributes = getAttributes(template.attributes);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
        CK_ATTRIBUTE[] getAttributes(CK_ATTRIBUTE[] attrs) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
            return combine(attributes, attrs);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
        /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
         * Combine two sets of attributes. The second set has precedence
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
         * over the first and overrides its settings.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
        private static CK_ATTRIBUTE[] combine(CK_ATTRIBUTE[] attrs1,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
                CK_ATTRIBUTE[] attrs2) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
            List<CK_ATTRIBUTE> attrs = new ArrayList<CK_ATTRIBUTE>();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
            for (CK_ATTRIBUTE attr : attrs1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
                if (attr.pValue != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
                    attrs.add(attr);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
            for (CK_ATTRIBUTE attr2 : attrs2) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
                long type = attr2.type;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
                for (CK_ATTRIBUTE attr1 : attrs1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
                    if (attr1.type == type) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
                        attrs.remove(attr1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
                if (attr2.pValue != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
                    attrs.add(attr2);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
            return attrs.toArray(A0);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
        public String toString() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
            return Arrays.asList(attributes).toString();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
}