1 /*
2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xerces.internal.dom;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.StringTokenizer;
26 import org.w3c.dom.DOMImplementation;
27 import org.w3c.dom.DOMImplementationList;
28 import org.w3c.dom.DOMImplementationSource;
29 
30 /**
31  * Supply one the right implementation, based upon requested features. Each
32  * implemented <code>DOMImplementationSource</code> object is listed in the
33  * binding-specific list of available sources so that its
34  * <code>DOMImplementation</code> objects are made available.
35  *
36  * <p>See also the
37  * <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMImplementationSource'>
38  * Document Object Model (DOM) Level 3 Core Specification</a>.
39  *
40  * @xerces.internal
41  *
42  * @LastModified: Oct 2017
43  */
44 public class DOMImplementationSourceImpl
45     implements DOMImplementationSource {
46 
47     /**
48      * A method to request a DOM implementation.
49      * @param features A string that specifies which features are required.
50      *   This is a space separated list in which each feature is specified
51      *   by its name optionally followed by a space and a version number.
52      *   This is something like: "XML 1.0 Traversal Events 2.0"
53      * @return An implementation that has the desired features, or
54      *   <code>null</code> if this source has none.
55      */
getDOMImplementation(String features)56     public DOMImplementation getDOMImplementation(String features) {
57         // first check whether the CoreDOMImplementation would do
58         DOMImplementation impl =
59             CoreDOMImplementationImpl.getDOMImplementation();
60         if (testImpl(impl, features)) {
61             return impl;
62         }
63         // if not try the DOMImplementation
64         impl = DOMImplementationImpl.getDOMImplementation();
65         if (testImpl(impl, features)) {
66             return impl;
67         }
68 
69         return null;
70     }
71 
72     /**
73      * A method to request a list of DOM implementations that support the
74      * specified features and versions, as specified in .
75      * @param features A string that specifies which features and versions
76      *   are required. This is a space separated list in which each feature
77      *   is specified by its name optionally followed by a space and a
78      *   version number. This is something like: "XML 3.0 Traversal +Events
79      *   2.0"
80      * @return A list of DOM implementations that support the desired
81      *   features.
82      */
getDOMImplementationList(String features)83     public DOMImplementationList getDOMImplementationList(String features) {
84         // first check whether the CoreDOMImplementation would do
85         DOMImplementation impl = CoreDOMImplementationImpl.getDOMImplementation();
86         final List<DOMImplementation> implementations = new ArrayList<>();
87         if (testImpl(impl, features)) {
88             implementations.add(impl);
89         }
90         impl = DOMImplementationImpl.getDOMImplementation();
91         if (testImpl(impl, features)) {
92             implementations.add(impl);
93         }
94 
95         return new DOMImplementationListImpl(implementations);
96     }
97 
testImpl(DOMImplementation impl, String features)98     boolean testImpl(DOMImplementation impl, String features) {
99 
100         StringTokenizer st = new StringTokenizer(features);
101         String feature = null;
102         String version = null;
103 
104         if (st.hasMoreTokens()) {
105            feature = st.nextToken();
106         }
107         while (feature != null) {
108            boolean isVersion = false;
109            if (st.hasMoreTokens()) {
110                char c;
111                version = st.nextToken();
112                c = version.charAt(0);
113                switch (c) {
114                case '0': case '1': case '2': case '3': case '4':
115                case '5': case '6': case '7': case '8': case '9':
116                    isVersion = true;
117                }
118            } else {
119                version = null;
120            }
121            if (isVersion) {
122                if (!impl.hasFeature(feature, version)) {
123                    return false;
124                }
125                if (st.hasMoreTokens()) {
126                    feature = st.nextToken();
127                } else {
128                    feature = null;
129                }
130            } else {
131                if (!impl.hasFeature(feature, null)) {
132                    return false;
133                }
134                feature = version;
135            }
136         }
137         return true;
138     }
139 }
140