/** * Functions on zip files. * * @author BaseX Team 2005-14, BSD License * @author Christian Gruen */ abstract class ZipFn extends StandardFunc { /** QName. */ static final QNm Q_FILE = QNm.get(ZIP_PREFIX, "file", ZIP_URI); /** QName. */ static final QNm Q_DIR = QNm.get(ZIP_PREFIX, "dir", ZIP_URI); /** QName. */ static final QNm Q_ENTRY = QNm.get(ZIP_PREFIX, "entry", ZIP_URI); /** Attribute: href. */ static final byte[] HREF = token("href"); /** Attribute: name. */ static final byte[] NAME = token("name"); }
/** * Finds similar function names and throws an error message. * * @param name function name * @param ii input info * @throws QueryException query exception */ public void funError(final QNm name, final InputInfo ii) throws QueryException { // find global function Functions.get().error(name, ii); // find similar local function final Levenshtein ls = new Levenshtein(); final byte[] nm = lc(name.local()); for (final UserFunc f : funcs) { if (ls.similar(nm, lc(f.name.local()), 0)) { FUNSIMILAR.thrw(ii, name.string(), f.name.string()); } } }
/** * Adds a local function. * * @param fun function instance * @param ii input info * @return function id * @throws QueryException query exception */ public int add(final UserFunc fun, final InputInfo ii) throws QueryException { final QNm name = fun.name; final byte[] uri = name.uri(); if (uri.length == 0) FUNNONS.thrw(ii, name.string()); if (NSGlobal.reserved(uri)) { if (fun.declared) NAMERES.thrw(ii, name.string()); funError(name, ii); } final byte[] ln = name.local(); for (int l = 0; l < funcs.length; ++l) { final QNm qn = funcs[l].name; final byte[] u = qn.uri(); final byte[] nm = qn.local(); if (eq(ln, nm) && eq(uri, u) && fun.args.length == funcs[l].args.length) { // declare function that has been called before if (!funcs[l].declared) { funcs[l] = fun; return l; } // duplicate declaration FUNCDEFINED.thrw(ii, fun.name.string()); } } // add function skeleton funcs = Array.add(funcs, fun); calls = Array.add(calls, new UserFuncCall[0]); return funcs.length - 1; }
/** * Returns the specified function. * * @param name function qname * @param args optional arguments * @param ii input info * @return function instance * @throws QueryException query exception */ public StandardFunc get(final QNm name, final Expr[] args, final InputInfo ii) throws QueryException { final int id = id(name.id()); if (id == 0) return null; // create function final Function fl = funcs[id]; if (!eq(fl.uri(), name.uri())) return null; final StandardFunc f = fl.get(ii, args); // check number of arguments if (args.length < fl.min || args.length > fl.max) XPARGS.thrw(ii, fl); return f; }
/** * Reads an element as a gml node. Returns a geometry element or {@code null} if the element does * not match one of the specified types. * * @param node xml node containing gml object(s) * @param names allowed geometry types * @return geometry, or {@code null} * @throws QueryException query exception */ private static Geometry geo(final ANode node, final QNm... names) throws QueryException { if (node.type != NodeType.ELM) throw EXPTYPE_X_X_X.get(null, NodeType.ELM, node.type, node); final QNm qname = node.qname(); for (final QNm geo : names) { if (!qname.eq(geo)) continue; // type found... create reader and geometry element try { final String input = node.serialize().toString(); final GMLReader gmlReader = new GMLReader(); final GeometryFactory geoFactory = new GeometryFactory(); return gmlReader.read(input, geoFactory); } catch (final Throwable ex) { throw GeoErrors.gmlReaderErr(ex); } } return null; }
/** * Throws an error if one of the pre-defined functions is similar to the specified function name. * * @param name function name * @param ii input info * @throws QueryException query exception */ public void error(final QNm name, final InputInfo ii) throws QueryException { // compare specified name with names of predefined functions final byte[] ln = name.local(); final Levenshtein ls = new Levenshtein(); for (int k = 1; k < size; ++k) { final int i = indexOf(keys[k], '}'); final byte[] u = substring(keys[k], 2, i); final byte[] l = substring(keys[k], i + 1); if (eq(ln, l)) { final byte[] ur = name.uri(); FUNSIMILAR.thrw( ii, new TokenBuilder(NSGlobal.prefix(ur)).add(':').add(l), new TokenBuilder(NSGlobal.prefix(u)).add(':').add(l)); } else if (ls.similar(ln, l, 0)) { FUNSIMILAR.thrw(ii, name.string(), l); } } }
/** * Parses a jar descriptor. * * @param io XML input * @return jar descriptor container * @throws QueryException query exception */ public JarDesc parse(final IO io) throws QueryException { final JarDesc desc = new JarDesc(); try { final ANode node = new DBNode(io).children().next(); for (final ANode next : node.children()) { if (next.type != NodeType.ELM) continue; final QNm name = next.qname(); // ignore namespace to improve compatibility if (eq(JAR, name.local())) desc.jars.add(next.string()); else if (eq(CLASS, name.local())) desc.classes.add(next.string()); // [CG] Packaging: add warning if unknown elements are encountered } if (desc.jars.isEmpty()) throw BXRE_JARDESC_X.get(info, NOJARS); else if (desc.classes.isEmpty()) throw BXRE_JARDESC_X.get(info, NOCLASSES); return desc; } catch (final IOException ex) { throw BXRE_JARFAIL_X.get(info, ex); } }
/** * Returns a new Java function instance. * * @param name function name * @param args arguments * @param qc query context * @param sc static context * @param ii input info * @return Java function or {@code null} * @throws QueryException query exception */ static JavaMapping get( final QNm name, final Expr[] args, final QueryContext qc, final StaticContext sc, final InputInfo ii) throws QueryException { final byte[] uri = name.uri(); // check if URI starts with "java:" prefix (if yes, module must be Java code) final boolean java = startsWith(uri, JAVAPREF); // rewrite function name: convert dashes to upper-case initials final String local = camelCase(string(name.local())); // check imported Java modules final String path = camelCase(toPath(java ? substring(uri, JAVAPREF.length) : uri)); final ModuleLoader modules = qc.resources.modules(); final Object jm = modules.findImport(path); if (jm != null) { final Method meth = getModMethod(jm, path, local, args.length, qc, ii); if (meth != null) return new JavaModuleFunc(sc, ii, jm, meth, args); } // only allowed with administrator permissions if (!qc.context.user.has(Perm.ADMIN)) return null; // check addressed class try { return new JavaFunc(sc, ii, modules.findClass(path), local, args); } catch (final ClassNotFoundException ex) { // only throw exception if "java:" prefix was explicitly specified if (java) throw FUNCJAVA_X.get(ii, path); } catch (final Throwable th) { throw JAVAINIT_X.get(ii, th); } // no function found return null; }
/** * Returns a parameter. * * @param value value * @param name name * @param declared variable declaration flags * @return parameter * @throws QueryException HTTP exception */ private RestXqParam param(final Value value, final QNm name, final boolean[] declared) throws QueryException { // [CG] RESTXQ: allow identical field names? final long vs = value.size(); if (vs < 2) error(ANN_PARAMS, "%", name.string(), 2); // name of parameter final String key = toString(value.itemAt(0), name); // variable template final QNm qnm = checkVariable(toString(value.itemAt(1), name), declared); // default value final ValueBuilder vb = new ValueBuilder(); for (int v = 2; v < vs; v++) vb.add(value.itemAt(v)); return new RestXqParam(qnm, key, vb.value()); }
/** * Returns an instance of a with the specified name and number of arguments, or {@code null}. * * @param name name of the function * @param args optional arguments * @param dyn compile-/run-time flag * @param ctx query context * @param ii input info * @return function instance * @throws QueryException query exception */ public static TypedFunc get( final QNm name, final Expr[] args, final boolean dyn, final QueryContext ctx, final InputInfo ii) throws QueryException { // get namespace and local name // parse data type constructors if (eq(name.uri(), XSURI)) { final byte[] ln = name.local(); final AtomType type = AtomType.find(name, false); if (type == null) { final Levenshtein ls = new Levenshtein(); for (final AtomType t : AtomType.values()) { if (t.par != null && t != AtomType.NOT && t != AtomType.AAT && t != AtomType.BIN && ls.similar(lc(ln), lc(t.string()), 0)) FUNSIMILAR.thrw(ii, name.string(), t.string()); } } // no constructor function found, or abstract type specified if (type == null || type == AtomType.NOT || type == AtomType.AAT) { FUNCUNKNOWN.thrw(ii, name.string()); } if (args.length != 1) FUNCTYPE.thrw(ii, name.string()); final SeqType to = SeqType.get(type, Occ.ZERO_ONE); return TypedFunc.constr(new Cast(ii, args[0], to), to); } // pre-defined functions final StandardFunc fun = Functions.get().get(name, args, ii); if (fun != null) { if (!ctx.sc.xquery3 && fun.xquery3()) FEATURE30.thrw(ii); for (final Function f : Function.UPDATING) { if (fun.sig == f) { ctx.updating(true); break; } } return new TypedFunc(fun, fun.sig.type(args.length)); } // user-defined function final TypedFunc tf = ctx.funcs.get(name, args, ii); if (tf != null) return tf; // Java function (only allowed with administrator permissions) final JavaMapping jf = JavaMapping.get(name, args, ctx, ii); if (jf != null) return TypedFunc.java(jf); // add user-defined function that has not been declared yet if (!dyn && FuncType.find(name) == null) return ctx.funcs.add(name, args, ii, ctx); // no function found return null; }
/** * This module contains geo spatial functions for the Geo module. * * @author BaseX Team 2005-14, BSD License * @author Masoumeh Seydi */ public final class Geo extends QueryModule { /** GML URI. */ private static final byte[] URI = token("http://www.opengis.net/gml"); /** Prefix: "gml". */ private static final String GML = "gml"; /** QName gml:Point. */ private static final QNm Q_GML_POINT = QNm.get(GML, "Point", URI); /** QName gml:MultiPoint. */ private static final QNm Q_GML_MULTIPOINT = QNm.get(GML, "MultiPoint", URI); /** QName gml:LineString. */ private static final QNm Q_GML_LINESTRING = QNm.get(GML, "LineString", URI); /** QName gml:LinearRing. */ private static final QNm Q_GML_LINEARRING = QNm.get(GML, "LinearRing", URI); /** QName gml:Polygon. */ private static final QNm Q_GML_POLYGON = QNm.get(GML, "Polygon", URI); /** QName gml:MultiPolygon. */ private static final QNm Q_GML_MULTIPOLYGON = QNm.get(GML, "MultiPolygon", URI); /** QName gml:MultiLineString. */ private static final QNm Q_GML_MULTILINESTRING = QNm.get(GML, "MultiLineString", URI); /** Array containing all QNames. */ private static final QNm[] QNAMES = { Q_GML_POINT, Q_GML_LINESTRING, Q_GML_POLYGON, Q_GML_MULTIPOINT, Q_GML_MULTILINESTRING, Q_GML_MULTIPOLYGON, Q_GML_LINEARRING }; /** * Returns the dimension of an item. * * @param node xml element containing gml object(s) * @return dimension * @throws QueryException query exception */ @Deterministic public Int dimension(final ANode node) throws QueryException { return Int.get(checkGeo(node).getDimension()); } /** * Returns the name of the geometry type in the GML namespace, or the empty sequence. * * @param node xml element containing gml object(s) * @return geometry type * @throws QueryException query exception */ @Deterministic public QNm geometryType(final ANode node) throws QueryException { return new QNm(GML + ':' + checkGeo(node).getGeometryType(), URI); } /** * Returns the name of the geometry type in the GML namespace, or the empty sequence. * * @param node xml element containing gml object(s) * @return integer value of CRS of the geometry * @throws QueryException query exception */ @Deterministic public Uri srid(final ANode node) throws QueryException { return Uri.uri(token(checkGeo(node).getSRID())); } /** * Returns the gml:Envelope of the specified geometry. The envelope is the minimum bounding box of * this geometry. * * @param node xml element containing gml object(s) * @return envelop element * @throws QueryException query exception */ @Deterministic public ANode envelope(final ANode node) throws QueryException { return gmlWriter(checkGeo(node).getEnvelope()); } /** * Returns the WKT format of a geometry. * * @param node xml element containing gml object(s) * @return Well-Known Text geometry representation * @throws QueryException query exception */ @Deterministic public Str asText(final ANode node) throws QueryException { return Str.get(new WKTWriter().write(checkGeo(node))); } /** * Returns the WKB format of a geometry. * * @param node xml element containing gml object(s) * @return Well-Known Binary geometry representation * @throws QueryException query exception */ @Deterministic public B64 asBinary(final ANode node) throws QueryException { return new B64(new WKBWriter().write(checkGeo(node))); } /** * Returns a boolean value which shows if the specified geometry is empty or not. * * @param node xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln isEmpty(final ANode node) throws QueryException { return Bln.get(node != null && checkGeo(node) != null); } /** * Returns a boolean value which shows if the specified geometry is simple or not, which has no * anomalous geometric points, such as self intersection or self tangency. * * @param node xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln isSimple(final ANode node) throws QueryException { return Bln.get(checkGeo(node).isSimple()); } /** * Returns the boundary of the geometry, in GML. The return value is a sequence of either * gml:Point or gml:LinearRing elements. * * @param node xml element containing gml object(s) * @return boundary element (geometry) * @throws QueryException query exception */ @Deterministic public ANode boundary(final ANode node) throws QueryException { return gmlWriter(checkGeo(node).getBoundary()); } /** * Returns a boolean value that shows if two geometries are equal or not. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln equals(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.equals(geo2)); } /** * Returns a boolean value that shows if this geometry is disjoint to another geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln disjoint(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.disjoint(geo2)); } /** * Returns a boolean value that shows if this geometry intersects another geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln intersects(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.intersects(geo2)); } /** * Returns a boolean value that shows if this geometry touches the specified geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln touches(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.touches(geo2)); } /** * Returns a boolean value that shows if this geometry crosses the specified geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln crosses(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.crosses(geo2)); } /** * Returns a boolean value that shows if this geometry is within the specified geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln within(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.within(geo2)); } /** * Returns a boolean value that shows if this geometry contains the specified geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln contains(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.contains(geo2)); } /** * Returns a boolean value that shows if this geometry overlaps the specified geometry. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln overlaps(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.overlaps(geo2)); } /** * Returns a boolean value that shows if whether relationships between the boundaries, interiors * and exteriors of two geometries match the pattern specified in intersection-matrix-pattern. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @param intersectionMatrix intersection matrix for two geometries * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln relate(final ANode node1, final ANode node2, final Str intersectionMatrix) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Bln.get(geo1.relate(geo2, intersectionMatrix.toJava())); } /** * Returns the shortest distance in the units of the spatial reference system of geometry, between * the geometries. The distance is the distance between a point on each of the geometries. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return distance double value * @throws QueryException query exception */ @Deterministic public Dbl distance(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return Dbl.get(geo1.distance(geo2)); } /** * Returns a polygon that represents all Points whose distance from this geometric object is less * than or equal to distance. The returned element must be either gml:Polygon, gml:LineString or * gml:Point. * * @param node xml element containing gml object(s) * @param distance specific distance from the $geometry (the buffer width) * @return buffer geometry as gml element * @throws QueryException query exception */ @Deterministic public ANode buffer(final ANode node, final Dbl distance) throws QueryException { return gmlWriter(checkGeo(node).buffer(distance.dbl())); } /** * Returns the convex hull geometry of a geometry in GML, or the empty sequence. The returned * element must be either gml:Polygon, gml:LineString or gml:Point. * * @param node xml element containing gml object(s) * @return convex hull geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode convexHull(final ANode node) throws QueryException { return gmlWriter(checkGeo(node).convexHull()); } /** * Returns a geometric object representing the Point set intersection of two geometries. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return intersection geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode intersection(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return gmlWriter(geo1.intersection(geo2)); } /** * Returns a geometric object that represents the Point set union of two geometries. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return union geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode union(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return gmlWriter(geo1.union(geo2)); } /** * Returns a geometric object that represents the Point set difference of two geometries. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return difference geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode difference(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return gmlWriter(geo1.difference(geo2)); } /** * Returns a geometric object that represents the Point set symmetric difference of two * geometries. * * @param node1 xml element containing gml object(s) * @param node2 xml element containing gml object(s) * @return symmetric difference geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode symDifference(final ANode node1, final ANode node2) throws QueryException { final Geometry geo1 = checkGeo(node1); final Geometry geo2 = checkGeo(node2); return gmlWriter(geo1.symDifference(geo2)); } /** * Returns number of geometries in a geometry collection, or 1 if the input is not a collection. * * @param node xml element containing gml object(s) * @return integer value of number of geometries * @throws QueryException query exception */ @Deterministic public Int numGeometries(final ANode node) throws QueryException { return Int.get(checkGeo(node).getNumGeometries()); } /** * Returns the nth geometry of a geometry collection, or the geometry if the input is not a * collection. * * @param node xml element containing gml object(s) * @param number integer number as the index of nth geometry * @return geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode geometryN(final ANode node, final Int number) throws QueryException { final Geometry geo = checkGeo(node); final long n = number.itr(); if (n < 1 || n > geo.getNumGeometries()) throw GeoErrors.outOfRangeIdx(number); return gmlWriter(geo.getGeometryN((int) n - 1)); } /** * Returns the x-coordinate value for point. * * @param node xml element containing gml object(s) * @return x double value * @throws QueryException query exception */ @Deterministic public Dbl x(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_POINT); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Point"); return Dbl.get(geo.getCoordinate().x); } /** * Returns the y-coordinate value for point. * * @param node xml element containing gml object(s) * @return y double value * @throws QueryException query exception */ @Deterministic public Dbl y(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_POINT); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Point"); return Dbl.get(geo.getCoordinate().y); } /** * Returns the z-coordinate value for point. * * @param node xml element containing gml object(s) * @return z double value * @throws QueryException query exception */ @Deterministic public Dbl z(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_POINT); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Line"); return Dbl.get(geo.getCoordinate().z); } /** * Returns the length of this Geometry. Linear geometries return their length. Areal geometries * return their parameter. Others return 0.0 * * @param node xml element containing gml object(s) * @return length double value * @throws QueryException query exception */ @Deterministic public Dbl length(final ANode node) throws QueryException { return Dbl.get(checkGeo(node).getLength()); } /** * Returns the start point of a line. * * @param node xml element containing gml object(s) * @return start point geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode startPoint(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Line"); return gmlWriter(((LineString) geo).getStartPoint()); } /** * Returns the end point of a line. * * @param node xml element containing gml object(s) * @return end point geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode endPoint(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Line"); return gmlWriter(((LineString) geo).getEndPoint()); } /** * Checks if the line is closed loop. That is, if the start Point is same with end Point. * * @param node xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln isClosed(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING, Q_GML_MULTILINESTRING); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Line"); return Bln.get( geo instanceof LineString ? ((LineString) geo).isClosed() : ((MultiLineString) geo).isClosed()); } /** * Return a boolean value that shows weather the line is a ring or not. A line is a ring if it is * closed and simple. * * @param node xml element containing gml object(s) * @return boolean value * @throws QueryException query exception */ @Deterministic public Bln isRing(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Line"); return Bln.get(((LineString) geo).isRing()); } /** * Returns the number of points in a geometry. * * @param node xml element containing gml object(s) * @return number of points int value * @throws QueryException query exception */ @Deterministic public Int numPoints(final ANode node) throws QueryException { return Int.get(checkGeo(node).getNumPoints()); } /** * Returns the nth point of a line. * * @param node xml element containing gml object(s) * @param number index of i-th point * @return n-th point as a gml element * @throws QueryException query exception */ @Deterministic public ANode pointN(final ANode node, final Int number) throws QueryException { final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Line"); final int max = geo.getNumPoints(); final long n = number.itr(); if (n < 1 || n > max) throw GeoErrors.outOfRangeIdx(number); return gmlWriter(((LineString) geo).getPointN((int) n - 1)); } /** * Returns the area of a Geometry. Areal Geometries have a non-zero area. Returns zero for Point * and Lines. * * @param node xml element containing gml object(s) * @return geometry area as a double vaue * @throws QueryException query exception */ @Deterministic public Dbl area(final ANode node) throws QueryException { return Dbl.get(checkGeo(node).getArea()); } /** * Returns the mathematical centroid of the geometry as a gml:Point. The point is not guaranteed * to be on the surface. * * @param node xml element containing gml object(s) * @return centroid geometry as a gml element * @throws QueryException query exception */ @Deterministic public ANode centroid(final ANode node) throws QueryException { return gmlWriter(checkGeo(node).getCentroid()); } /** * Returns a gml:Point that is interior of this geometry. If it cannot be inside the geometry, * then it will be on the boundary. * * @param node xml element containing gml object(s) * @return a point as a gml element * @throws QueryException query exception */ @Deterministic public ANode pointOnSurface(final ANode node) throws QueryException { return gmlWriter(checkGeo(node).getInteriorPoint()); } /** * Returns the outer ring of a polygon, in GML. * * @param node xml element containing gml object(s) * @return exterior ring geometry (LineString) as a gml element * @throws QueryException query exception */ @Deterministic public ANode exteriorRing(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_POLYGON); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Polygon"); return gmlWriter(((Polygon) geo).getExteriorRing()); } /** * Returns the number of interior rings in a polygon. * * @param node xml element containing gml object(s) * @return integer number of interior rings * @throws QueryException query exception */ @Deterministic public Int numInteriorRing(final ANode node) throws QueryException { final Geometry geo = geo(node, Q_GML_POLYGON); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Polygon"); return Int.get(((Polygon) geo).getNumInteriorRing()); } /** * Returns the nth geometry of a geometry collection. * * @param node xml element containing gml object(s) * @param number index of i-th interior ring * @return n-th interior ring geometry (LineString) as a gml element * @throws QueryException query exception */ @Deterministic public ANode interiorRingN(final ANode node, final Int number) throws QueryException { final Geometry geo = geo(node, Q_GML_POLYGON); if (geo == null && checkGeo(node) != null) throw GeoErrors.geoType(node.qname().local(), "Polygon"); final long n = number.itr(); final int max = ((Polygon) geo).getNumInteriorRing(); if (n < 1 || n > max) throw GeoErrors.outOfRangeIdx(number); return gmlWriter(((Polygon) geo).getInteriorRingN((int) n - 1)); } // PRIVATE METHODS (hidden from user of module) ======================================== /** * Reads an element as a gml node. Returns a geometry element or throws an exception if the * element is of the wrong type. * * @param node xml node containing gml object(s) * @return geometry * @throws QueryException query exception */ private Geometry checkGeo(final ANode node) throws QueryException { final Geometry geo = geo(node, QNAMES); if (geo == null) throw GeoErrors.unrecognizedGeo(node.qname().local()); return geo; } /** * Reads an element as a gml node. Returns a geometry element or {@code null} if the element does * not match one of the specified types. * * @param node xml node containing gml object(s) * @param names allowed geometry types * @return geometry, or {@code null} * @throws QueryException query exception */ private static Geometry geo(final ANode node, final QNm... names) throws QueryException { if (node.type != NodeType.ELM) throw EXPTYPE_X_X_X.get(null, NodeType.ELM, node.type, node); final QNm qname = node.qname(); for (final QNm geo : names) { if (!qname.eq(geo)) continue; // type found... create reader and geometry element try { final String input = node.serialize().toString(); final GMLReader gmlReader = new GMLReader(); final GeometryFactory geoFactory = new GeometryFactory(); return gmlReader.read(input, geoFactory); } catch (final Throwable ex) { throw GeoErrors.gmlReaderErr(ex); } } return null; } /** * Writes an geometry and returns a string representation of the geometry. * * @param geometry geometry * @return DBNode database node * @throws QueryException exception */ private DBNode gmlWriter(final Geometry geometry) throws QueryException { final String geo; try { // write geometry and add namespace declaration geo = new GMLWriter() .write(geometry) .replaceAll("^<gml:(.*?)>", "<gml:$1 xmlns:gml='" + string(URI) + "'>"); } catch (final Exception ex) { throw GeoErrors.gmlWriterErr(ex); } try { final IO io = new IOContent(geo); return new DBNode(MemBuilder.build(new XMLParser(io, queryContext.context.options))); } catch (final IOException ex) { throw IOERR_X.get(null, ex); } } }
/** * Returns an index to the specified function, or {@code -1}. * * @param name name of the function * @param args optional arguments * @return function instance */ private int indexOf(final QNm name, final Expr[] args) { for (int id = 0; id < funcs.length; ++id) { if (name.eq(funcs[id].name) && args.length == funcs[id].args.length) return id; } return -1; }
/** * Returns the specified value as an atomic string. * * @param value value * @param name name * @return string * @throws QueryException HTTP exception */ private String toString(final Value value, final QNm name) throws QueryException { if (!(value instanceof Str)) error(ANN_STRING, "%", name.string(), value); return ((Str) value).toJava(); }
/** * Checks a function for RESTFful annotations. * * @return {@code true} if module contains relevant annotations * @throws QueryException query exception */ boolean analyze() throws QueryException { // parse all annotations final EnumSet<HTTPMethod> mth = EnumSet.noneOf(HTTPMethod.class); final boolean[] declared = new boolean[function.args.length]; boolean found = false; final int as = function.ann.size(); for (int a = 0; a < as; a++) { final QNm name = function.ann.names[a]; final Value value = function.ann.values[a]; final byte[] local = name.local(); final byte[] uri = name.uri(); final boolean rexq = eq(uri, QueryText.RESTXQURI); if (rexq) { if (eq(PATH, local)) { // annotation "path" if (path != null) error(ANN_TWICE, "%", name.string()); path = new RestXqPath(toString(value, name)); for (final String s : path) { if (s.trim().startsWith("{")) checkVariable(s, AtomType.AAT, declared); } } else if (eq(CONSUMES, local)) { // annotation "consumes" strings(value, name, consumes); } else if (eq(PRODUCES, local)) { // annotation "produces" strings(value, name, produces); } else if (eq(QUERY_PARAM, local)) { // annotation "query-param" queryParams.add(param(value, name, declared)); } else if (eq(FORM_PARAM, local)) { // annotation "form-param" formParams.add(param(value, name, declared)); } else if (eq(HEADER_PARAM, local)) { // annotation "header-param" headerParams.add(param(value, name, declared)); } else if (eq(COOKIE_PARAM, local)) { // annotation "cookie-param" cookieParams.add(param(value, name, declared)); } else { // method annotations final HTTPMethod m = HTTPMethod.get(string(local)); if (m == null) error(ANN_UNKNOWN, "%", name.string()); if (!value.isEmpty()) { // remember post/put variable if (requestBody != null) error(ANN_TWICE, "%", name.string()); if (m != POST && m != PUT) error(METHOD_VALUE, m); requestBody = checkVariable(toString(value, name), declared); } if (mth.contains(m)) error(ANN_TWICE, "%", name.string()); mth.add(m); } } else if (eq(uri, QueryText.OUTPUTURI)) { // serialization parameters final String key = string(local); final String val = toString(value, name); if (output.get(key) == null) error(UNKNOWN_SER, key); output.set(key, val); } found |= rexq; } if (!mth.isEmpty()) methods = mth; if (found) { if (path == null) error(ANN_MISSING, PATH); for (int i = 0; i < declared.length; i++) if (!declared[i]) error(VAR_UNDEFINED, function.args[i].name.string()); } return found; }
/** * Functions on relational databases. * * @author BaseX Team 2005-15, BSD License * @author Rositsa Shadura */ public final class SqlConnect extends SqlFn { /** QName. */ private static final QNm Q_OPTIONS = QNm.get(SQL_PREFIX, "options", SQL_URI); /** Auto-commit mode. */ private static final String AUTO_COMM = "autocommit"; /** User. */ private static final String USER = "******"; /** Password. */ private static final String PASS = "******"; @Override public Item item(final QueryContext qc, final InputInfo ii) throws QueryException { checkCreate(qc); // URL to relational database final String url = string(toToken(exprs[0], qc)); final JDBCConnections jdbc = jdbc(qc); try { if (exprs.length > 2) { // credentials final String user = string(toToken(exprs[1], qc)); final String pass = string(toToken(exprs[2], qc)); if (exprs.length == 4) { // connection options final Options opts = toOptions(3, Q_OPTIONS, new Options(), qc); // extract auto-commit mode from options boolean ac = true; final HashMap<String, String> options = opts.free(); final String commit = options.get(AUTO_COMM); if (commit != null) { ac = Strings.yes(commit); options.remove(AUTO_COMM); } // connection properties final Properties props = connProps(options); props.setProperty(USER, user); props.setProperty(PASS, pass); // open connection final Connection conn = getConnection(url, props); // set auto/commit mode conn.setAutoCommit(ac); return Int.get(jdbc.add(conn)); } return Int.get(jdbc.add(getConnection(url, user, pass))); } return Int.get(jdbc.add(getConnection(url))); } catch (final SQLException ex) { throw BXSQ_ERROR_X.get(info, ex); } } /** * Parses connection options. * * @param options options * @return connection properties */ private static Properties connProps(final HashMap<String, String> options) { final Properties props = new Properties(); for (final Entry<String, String> entry : options.entrySet()) { props.setProperty(entry.getKey(), entry.getValue()); } return props; } }
/** * Checks if the specified item is a string or element. * * @param it item to be checked * @return item * @throws QueryException query exception */ private Item checkElmStr(final Item it) throws QueryException { if (it instanceof AStr || TEST.eq(it)) return it; throw ELMSTRTYPE.thrw(info, Q_ENTRY.string(), it.type); }