xml.xpath.ext/src/org/netbeans/modules/xml/xpath/ext/XPathUtils.java
author Milutin Kristofic <mkristofic@netbeans.org>
Mon, 30 Jan 2017 14:30:54 +0100
changeset 1583 fe20f672a61a
parent 1305 619e3fca5c2f
permissions -rw-r--r--
Added Missing copyright information in source files
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2009-2017 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Sun Microsystems, Inc. Portions Copyright 2009-2010 Sun
    31  * Microsystems, Inc. All Rights Reserved.
    32  *
    33  * If you wish your version of this file to be governed by only the CDDL
    34  * or only the GPL Version 2, indicate your decision by adding
    35  * "[Contributor] elects to include this software in this distribution
    36  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    37  * single choice of license, a recipient has the option to distribute
    38  * your version of this file under either the CDDL, the GPL Version 2 or
    39  * to extend the choice of license to its licensees as provided above.
    40  * However, if you add GPL Version 2 code and therefore, elected the GPL
    41  * Version 2 license, then the option applies only if the new code is
    42  * made subject to such option by the copyright holder.
    43  */
    44 /*
    45  * Utils.java
    46  * 
    47  * Created on 31.08.2007, 15:40:45
    48  * 
    49  * To change this template, choose Tools | Templates
    50  * and open the template in the editor.
    51  */
    52 
    53 package org.netbeans.modules.xml.xpath.ext;
    54 
    55 import java.util.ArrayList;
    56 import java.util.Collection;
    57 import java.util.List;
    58 import java.util.Set;
    59 import javax.xml.namespace.NamespaceContext;
    60 import javax.xml.namespace.QName;
    61 import org.netbeans.modules.xml.schema.model.ElementReference;
    62 import org.netbeans.modules.xml.schema.model.Form;
    63 import org.netbeans.modules.xml.schema.model.GlobalAttribute;
    64 import org.netbeans.modules.xml.schema.model.GlobalElement;
    65 import org.netbeans.modules.xml.schema.model.LocalAttribute;
    66 import org.netbeans.modules.xml.schema.model.LocalElement;
    67 import org.netbeans.modules.xml.schema.model.Schema;
    68 import org.netbeans.modules.xml.schema.model.SchemaComponent;
    69 import org.netbeans.modules.xml.schema.model.SchemaModel;
    70 import org.netbeans.modules.xml.xpath.ext.schema.FindAllChildrenSchemaVisitor;
    71 import org.netbeans.modules.xml.xpath.ext.schema.FindChildrenSchemaVisitor;
    72 import org.netbeans.modules.xml.xpath.ext.schema.resolver.SchemaCompHolder;
    73 import org.netbeans.modules.xml.xpath.ext.schema.resolver.WrappingSchemaContext;
    74 import org.netbeans.modules.xml.xpath.ext.schema.resolver.XPathSchemaContext;
    75 import org.netbeans.modules.xml.xpath.ext.schema.resolver.XPathSchemaContext.SchemaCompPair;
    76 import org.netbeans.modules.xml.xpath.ext.spi.ExternalModelResolver;
    77 import org.netbeans.modules.xml.xpath.ext.spi.XPathCastResolver;
    78 import org.netbeans.modules.xml.xpath.ext.spi.XPathPseudoComp;
    79 import org.netbeans.modules.xml.xpath.ext.visitor.ExpressionComparatorVisitor;
    80 
    81 /**
    82  * Utility class.
    83  * 
    84  * @author nk160297
    85  */
    86 public class XPathUtils {
    87 
    88     public static boolean equal(Object o1, Object o2) {
    89         if (o1 == o2) return true;
    90         return (o1 == null || o2 == null) ? false : o1.equals(o2);
    91     }
    92 
    93     /**
    94      * Converts the qName to a String. 
    95      * Only the prefix and the local part is used. 
    96      * The namespace URI is ignored. 
    97      * 
    98      * This method is intended to print an entity.
    99      */ 
   100     public static String qNameObjectToString(QName qName) {
   101         String prefix = qName.getPrefix();
   102         if (prefix == null || prefix.length() == 0) {
   103             return qName.getLocalPart();
   104         } else {
   105             return prefix + ":" + qName.getLocalPart();
   106         }
   107                 
   108     }
   109     
   110     /**
   111      * Converts the qName to a String. 
   112      * Only the prefix and the namespace URI is used. 
   113      * The local part is ignored. 
   114      * 
   115      * This method is intended to print a namespace which is held in a QName.
   116      */ 
   117     public static String gNameNamespaceToString(QName qName) {
   118         String prefix = qName.getPrefix();
   119         String nsUri = qName.getNamespaceURI();
   120         //
   121         if (prefix == null || prefix.length() == 0) {
   122             return "{" + nsUri + "}";
   123         } else {
   124             return "{" + nsUri + "}" + prefix;
   125         }
   126     }
   127     
   128     /**
   129      * Check if the namespace URI is specified for the name. 
   130      * If the name isn't specified, then try resolve it from the prefix.
   131      * Returns the corrected name if possible. Otherwise returns old name.
   132      * @param nsContext
   133      * @param name
   134      * @return
   135      */
   136     public static QName resolvePrefix(NamespaceContext nsContext, QName name) {
   137         String nsUri = name.getNamespaceURI();
   138         if (nsUri == null || nsUri.length() == 0 && nsContext != null) {
   139             //
   140             String nsPrefix = name.getPrefix();
   141             nsUri = nsContext.getNamespaceURI(nsPrefix);
   142             //
   143             if (nsUri != null) {
   144                 String localPart = name.getLocalPart();
   145                 QName newName = new QName(nsUri, localPart);
   146                 name = newName;
   147             }
   148         }
   149         //
   150         return name;
   151     }
   152     
   153     public static boolean equalsIgnorNsUri(QName qName1, QName qName2) {
   154         return (qName1.getLocalPart().equals(qName2.getLocalPart())) && 
   155                 (qName1.getPrefix().equals(qName2.getPrefix()));
   156     }
   157     
   158     public static boolean samePredicatesArr(
   159             XPathPredicateExpression[] predArr1, 
   160             XPathPredicateExpression[] predArr2) {
   161         //
   162         if (predArr1 == predArr2) {
   163             return true;
   164         }
   165         if (predArr1 == null || predArr2 == null) {
   166             return false;
   167         }
   168         //
   169         // Compare predicates count
   170         int size1 = predArr1 == null ? 0 : predArr1.length;
   171         int size2 = predArr2 == null ? 0 : predArr2.length;
   172         if (size1 != size2) {
   173             return false;
   174         }
   175         // Compare predicates one by one
   176         //
   177         // It is implied that the order is the same. 
   178         // So the same sets of predicates but with different order 
   179         // are considered different. 
   180         for (int index = 0; index < size1; index++) {
   181             XPathPredicateExpression predicate1 = predArr1[index];
   182             XPathPredicateExpression predicate2 = predArr2[index];
   183             //
   184             XPathExpression predExpr1 = predicate1.getPredicate();
   185             XPathExpression predExpr2 = predicate2.getPredicate();
   186             //
   187             if (predExpr1 instanceof XPathSchemaContextHolder &&
   188                     predExpr2 instanceof XPathSchemaContextHolder) {
   189                 // If both predicate expressions are schema context holders,
   190                 // then compare contexts.
   191                 //
   192                 XPathSchemaContext ctxt1 =
   193                         ((XPathSchemaContextHolder)predExpr1).getSchemaContext();
   194                 XPathSchemaContext ctxt2 =
   195                         ((XPathSchemaContextHolder)predExpr2).getSchemaContext();
   196                 //
   197                 if (!equal(ctxt1, ctxt2)) {
   198                     return false;
   199                 }
   200             } else {
   201                 if (!ExpressionComparatorVisitor.equals(predExpr1, predExpr2)) {
   202                     return false;
   203                 }
   204             }
   205         }
   206         return true;
   207     }
   208     
   209     /**
   210      * Determines if a namespace prefix is required for the specified schema component. 
   211      * @param sComp
   212      * @return
   213      */
   214     public static boolean isPrefixRequired(SchemaComponent sComp) {
   215         if (sComp instanceof LocalElement) {
   216             Form form = ((LocalElement)sComp).getFormEffective();
   217             if (form == Form.QUALIFIED) {
   218                 return true;
   219             } else {
   220                 return false;
   221             }
   222         } else if (sComp instanceof GlobalElement) {
   223             return true;
   224         } else if (sComp instanceof LocalAttribute) {
   225             Form form = ((LocalAttribute)sComp).getFormEffective();
   226             if (form == Form.QUALIFIED) {
   227                 return true;
   228             } else {
   229                 return false;
   230             }
   231         } else if (sComp instanceof GlobalElement || 
   232                 sComp instanceof ElementReference || 
   233                 sComp instanceof GlobalAttribute) {
   234             // all global objects have to be with a prefix
   235             return true;
   236         }
   237         //
   238         assert true : "Unsupported schema component in the BPEL mapper tree!"; // NOI18N
   239         return false;
   240     }
   241     
   242     /**
   243      * Checks if the specified Schema component has any subcomponents.
   244      * @param sComp
   245      * @return
   246      */
   247     public static boolean hasSubcomponents(SchemaComponent sComp) {
   248         FindAllChildrenSchemaVisitor checker = 
   249                 new FindAllChildrenSchemaVisitor(true, true, true);
   250         checker.lookForSubcomponents(sComp);
   251         List<SchemaComponent> found = checker.getFound();
   252         return found != null && !found.isEmpty();
   253     }
   254     
   255     /**
   256      * Constructs a list of SchemaCompPair objects. Each SchemaCompPair represents 
   257      * a child Schema component of a parent. Parents are taken from the 
   258      * specified parent SchemaContext. The context can contain several schema
   259      * components. So children mean children of all possible parent components 
   260      * in current context. 
   261      * 
   262      * Childrent can be real children schema components or pseudo components. 
   263      * See XPathPseudoComp class.
   264      * 
   265      * @param xPathModel
   266      * @param parentSContext
   267      * @param lookForElements indicates if it necessary to add elements to 
   268      * the result list.
   269      * @param lookForAttributes indicates if it necessary to add attributes to 
   270      * the result list.
   271      * @param collectAny indicates if it necessary to add xsd:any or 
   272      * xsd:anyAttribute to the result list. 
   273      * @return result list
   274      */
   275     public static List<SchemaCompPair> findSubcomponents(
   276             XPathModel xPathModel, XPathSchemaContext parentSContext, 
   277             boolean lookForElements, boolean lookForAttributes, boolean collectAny) {
   278         //
   279         assert parentSContext != null;
   280         ArrayList<SchemaCompPair> result = new ArrayList<SchemaCompPair>();
   281         //
   282         XPathCastResolver castResolver = xPathModel == null ? null :
   283             xPathModel.getXPathCastResolver();
   284         Set<SchemaCompPair> parentCompPairSet = parentSContext.getSchemaCompPairs(); 
   285         //
   286         boolean processPseudoComp = 
   287                 castResolver != null && parentCompPairSet.size() == 1;
   288         //
   289         for (SchemaCompPair parentCompPair : parentCompPairSet) {
   290             SchemaCompHolder parentCompHolder = parentCompPair.getCompHolder();
   291             //
   292             FindAllChildrenSchemaVisitor visitor = 
   293                     new FindAllChildrenSchemaVisitor(
   294                     lookForElements, lookForAttributes, false);
   295             visitor.lookForSubcomponents(parentCompHolder.getSchemaComponent());
   296             //
   297             List<SchemaComponent> foundComps = visitor.getFound();
   298             for (SchemaComponent foundComp : foundComps) {
   299                 SchemaCompPair newPair = 
   300                         new SchemaCompPair(foundComp, parentCompHolder);
   301                 result.add(newPair);
   302             }
   303             //
   304             if (processPseudoComp) {
   305                 if (visitor.hasAny() || visitor.hasAnyAttribute()) {
   306                     List<XPathPseudoComp> pcList = 
   307                             castResolver.getPseudoCompList(parentSContext);
   308                     for (XPathPseudoComp pseudoComp : pcList) {
   309                         if (pseudoComp.isAttribute()) {
   310                             if (lookForAttributes && visitor.hasAnyAttribute()) {
   311                                 SchemaCompHolder scHolder = 
   312                                         SchemaCompHolder.Factory.construct(pseudoComp);
   313                                 SchemaCompPair newPair = 
   314                                         new SchemaCompPair(scHolder, parentCompHolder);
   315                                 result.add(newPair);
   316                             }
   317                         } else {
   318                             if (lookForElements && visitor.hasAny()) {
   319                                 SchemaCompHolder scHolder = 
   320                                         SchemaCompHolder.Factory.construct(pseudoComp);
   321                                 SchemaCompPair newPair = 
   322                                         new SchemaCompPair(scHolder, parentCompHolder);
   323                                 result.add(newPair);
   324                             }
   325                         }
   326                     }
   327                 }
   328             }
   329         }
   330         //
   331         return result;
   332     }
   333     
   334     /**
   335      * Collects a list of SchemaCompHoder objects, which are global accessible.
   336      * 
   337      * @param xPathModel
   338      * @param lookForElements indicates if it necessary to add elements to 
   339      * the result list.
   340      * @param lookForAttributes indicates if it necessary to add attributes to 
   341      * the result list.
   342      * @param collectAny indicates if it necessary to add xsd:any or 
   343      * xsd:anyAttribute to the result list. 
   344      * @return result list
   345      */
   346     public static List<SchemaComponent> findRootComponents(XPathModel xPathModel, 
   347             boolean lookForElements, boolean lookForAttributes, boolean collectAny) {
   348         //
   349         ArrayList<SchemaComponent> result = new ArrayList<SchemaComponent>();
   350         //
   351         ExternalModelResolver exModelResolver = xPathModel.getExternalModelResolver();
   352         //
   353         if (exModelResolver != null) {
   354             //
   355             // Look for all available root elements (attributes) 
   356             // in all available models
   357             // Pseudo components can be only inside of another schema components, 
   358             // So they can't be global. It doesn't necessary to look them here.
   359             Collection<SchemaModel> sModels = exModelResolver.getVisibleModels();
   360             for (SchemaModel sModel : sModels) {
   361                 Schema schema = sModel.getSchema();
   362                 if (schema != null) {
   363                     FindAllChildrenSchemaVisitor visitor =
   364                             new FindAllChildrenSchemaVisitor(
   365                             lookForElements, lookForAttributes, false);
   366                     visitor.lookForSubcomponents(schema);
   367                     //
   368                     List<SchemaComponent> foundComps = visitor.getFound();
   369                     result.addAll(foundComps);
   370                 }
   371             }
   372         }
   373         //
   374         return result;
   375     }
   376     
   377     /**
   378      * Returns the list of SchemaCompHolder components, which are children 
   379      * of the specified parent schema component component (and context) 
   380      * and have specified name and namespace. 
   381      * Usually only one component has to be returned. 
   382      * Not only real schema components can be childrent but also pseudo components, 
   383      * which are result of casting xsd:any or xsd:anyAttribute. 
   384      * 
   385      * @param xPathModel
   386      * @param parentContext
   387      * @param parent 
   388      * @param soughtName required name
   389      * @param soughtNamespace required namespace
   390      * @param isAttribute indicates if an attribute or element is required
   391      * It can be null. 
   392      * @return
   393      */
   394     public static List<SchemaCompHolder> getChildren(
   395             XPathModel xPathModel, XPathSchemaContext parentContext,
   396             SchemaComponent parent, String soughtName, 
   397             String soughtNamespace, boolean isAttribute) {
   398         List<SchemaComponent> found = null;
   399         boolean hasAny = false;
   400         boolean hasAnyAttribute = false;
   401         ArrayList<SchemaCompHolder> result = new ArrayList<SchemaCompHolder>();
   402         //
   403         FindChildrenSchemaVisitor visitor =
   404                 new FindChildrenSchemaVisitor(parentContext,
   405                 soughtName, soughtNamespace, isAttribute);
   406         visitor.lookForSubcomponent(parent);
   407         found = visitor.getFound();
   408         hasAny = visitor.hasAny();
   409         hasAnyAttribute = visitor.hasAnyAttribute();
   410         //
   411         if (found == null || found.isEmpty()) {
   412             //
   413             // try looking for Pseudo Components here
   414             XPathCastResolver castResolver = xPathModel.getXPathCastResolver();
   415             if (castResolver != null) {
   416                 List<XPathPseudoComp> pcList = 
   417                         castResolver.getPseudoCompList(parentContext);
   418                 if (pcList != null) {
   419                     for (XPathPseudoComp pseudoComp : pcList) {
   420                         if (!hasAnyAttribute && isAttribute) {
   421                             // AnyAttribute isn't supported
   422                             continue;
   423                         }
   424                         //
   425                         if (!hasAny && !isAttribute) {
   426                             // Any isn't supported
   427                             continue;
   428                         }
   429                         //
   430                         if (isAttribute != pseudoComp.isAttribute()) {
   431                             continue;
   432                         }
   433                         //
   434                         if (!(soughtName.equals(pseudoComp.getName()))) {
   435                             // Different name
   436                             continue;
   437                         }
   438                         if (!(soughtNamespace.equals(pseudoComp.getNamespace()))) {
   439                             // different namespace
   440                             continue;
   441                         } 
   442                         //
   443                         SchemaCompHolder compHolder = 
   444                                 SchemaCompHolder.Factory.construct(pseudoComp);
   445                         result.add(compHolder);
   446                     }
   447                 }
   448             }
   449         } else {
   450             convertToHolders(found, result);
   451         }
   452         //
   453         return result;
   454     }
   455     
   456     /**
   457      * Converts the list of Schema components to the list of SC holders 
   458      * @param scList
   459      * @param target
   460      */
   461     private static void convertToHolders(List<SchemaComponent> scList, 
   462             ArrayList<SchemaCompHolder> target) {
   463         for (SchemaComponent sc : scList) {
   464             SchemaCompHolder newHolder = SchemaCompHolder.Factory.construct(sc);
   465             if (newHolder != null) {
   466                 target.add(newHolder);
   467             }
   468         }
   469     }
   470 
   471     /**
   472      * Check if the input schema context is wrapping context, then takes 
   473      * unwrapped context recursively. 
   474      *
   475      * @param sContext
   476      * @return
   477      */
   478     public static XPathSchemaContext unwrap(XPathSchemaContext sContext) {
   479        if (sContext instanceof WrappingSchemaContext) {
   480            sContext = ((WrappingSchemaContext)sContext).getBaseContext();
   481            return unwrap(sContext);
   482        } else {
   483            return sContext;
   484        }
   485     }
   486 
   487 }