All Downloads are FREE. Search and download functionalities are using the official Maven repository.

annis.service.objects.Match Maven / Gradle / Ivy

There is a newer version: 4.0.0-beta.4
Show newest version
/*
 * Copyright 2009-2011 Collaborative Research Centre SFB 632 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package annis.service.objects;

import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.escape.Escaper;
import com.google.common.escape.Escapers;

/**
 * Represents a single match of an AQL query.
 * 
 * @author Thomas Krause {@literal }
 */
@XmlRootElement
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class Match implements Serializable {

    private final static Logger log = LoggerFactory.getLogger(Match.class);

    private final static Splitter matchSplitter = Splitter.on(" ").trimResults().omitEmptyStrings();
    private final static Splitter annoIDSplitter = Splitter.on("::").trimResults().limit(3);

    private static final Escaper spaceEscaper = Escapers.builder().addEscape(' ', "%20").addEscape('%', "%25").build();

    private List saltIDs;
    private List annos;

    public Match() {
        saltIDs = new ArrayList<>();
        annos = new ArrayList<>();
    }

    public Match(Collection originalIDs) {
        saltIDs = new ArrayList<>(originalIDs);
        annos = new ArrayList<>(saltIDs.size());
        for (int i = 0; i < saltIDs.size(); i++) {
            annos.add("");
        }
    }

    public Match(Collection originalIDs, Collection originalAnnos) {
        saltIDs = new ArrayList<>(originalIDs);
        annos = new ArrayList<>(originalAnnos);
    }

    public void addSaltId(URI id) {
        addSaltId(id, null);
    }

    public void addSaltId(URI id, String anno) {
        if (id != null) {
            saltIDs.add(id);
            if (anno == null) {
                annos.add("");
            } else {
                annos.add(anno);
            }
        }
    }

    /**
     * Get Salt IDs of the nodes that are part of the match.
     * 
     * @return a list of IDs as URI
     */
    @XmlElement(name = "id")
    public List getSaltIDs() {
        return saltIDs;
    }

    /**
     * @see #getSaltIDs()
     * @param saltIDs
     *                    the list of IDs as URI
     */
    public void setSaltIDs(List saltIDs) {
        this.saltIDs = saltIDs;
    }

    /**
     * Get the fully qualified annotation matched annotation names. This list must
     * be the same size as {@link #getSaltIDs() }. If no annotation is matched, the
     * list contains an entry with an empty string.
     * 
     * @return list of annotation names
     */
    @XmlElement(name = "anno")
    public List getAnnos() {
        if (annos == null || annos.size() != saltIDs.size()) {
            createEmptyAnnoList();
        }
        return annos;
    }

    public void setAnnos(List annos) {
        this.annos = annos;
    }

    private void createEmptyAnnoList() {
        if (saltIDs != null) {
            annos = new ArrayList<>(saltIDs.size());
            for (int i = 0; i < saltIDs.size(); i++) {
                annos.add("");
            }
        }
    }

    public static Match parseFromString(String raw) {
        return parseFromString(raw, ' ');
    }

    public static Match parseFromString(String raw, char separator) {
        Match match = new Match();

        Splitter splitter = matchSplitter;
        if (separator != ' ') {
            splitter = Splitter.on(separator).trimResults().omitEmptyStrings();
        }

        for (String singleMatch : splitter.split(raw)) {
            URI uri;

            String id = "";
            String anno = null;
            if (singleMatch.startsWith("salt:/")) {
                id = singleMatch;
            } else {
                // split into the annotation namespace/name and the salt URI
                List components = annoIDSplitter.splitToList(singleMatch);

                int componentsSize = components.size();

                Preconditions.checkArgument(componentsSize == 3 || componentsSize == 2,
                        "A match containing " + "annotation information always has to have the form "
                                + "ns::name::salt:/....  or name::salt:/....");

                String ns = "";
                String name = "";
                if (componentsSize == 3) {
                    id = components.get(2);
                    ns = components.get(0);
                    name = components.get(1);
                } else if (componentsSize == 2) {
                    id = components.get(1);
                    name = components.get(0);
                }
                if (ns.isEmpty()) {
                    anno = name;
                } else {
                    anno = ns + "::" + name;
                }
                // undo any escaping for the annotation part
                anno = anno.replace("%20", " ").replace("%25", "%").replace("%2C", ",");
            }

            try {
                
                uri = new URI(id).normalize();

                if (!"salt".equals(uri.getScheme())) {
                    throw new URISyntaxException("not a Salt id", uri.toString());
                }
                // check if the path ends with "/" (which was wrongly used by older ANNIS
                // versions)
                String path = uri.getPath();
                if (path.endsWith("/")) {
                    path = path.substring(0, path.length() - 1);
                }
                // recreate the URI with the decoded path (returned by getPath())
                uri  = new URI(uri.getScheme(), uri.getHost(), path, uri.getFragment());

            } catch (URISyntaxException ex) {
                log.error("Invalid syntax for ID " + singleMatch, ex);
                continue;
            }
            match.addSaltId(uri, anno);
        }

        return match;
    }

    /**
     * Returns a space separated list of all Salt IDs.
     * 
     * @return list of IDs as string
     */
    @Override
    public String toString() {
        if (saltIDs != null && annos != null) {
            Iterator itID = saltIDs.iterator();
            Iterator itAnno = annos.iterator();

            LinkedList asString = new LinkedList<>();
            while (itID.hasNext() && itAnno.hasNext()) {
                URI u = itID.next();
                String anno = itAnno.next();
                if (u != null) {
                    asString.add(singleMatchToString(u, anno));
                }
            }
            return Joiner.on(" ").join(asString);
        }
        return "";
    }

    public static String singleMatchToString(URI uri, String anno) {
        if (uri != null) {
            String v = uri.toASCIIString();
            if (anno != null && !anno.isEmpty()) {
                v = spaceEscaper.escape(anno) + "::" + uri;
            }
            return v;
        }
        return "";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((annos == null) ? 0 : annos.hashCode());
        result = prime * result + ((saltIDs == null) ? 0 : saltIDs.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Match other = (Match) obj;
        if (annos == null) {
            if (other.annos != null)
                return false;
        } else if (!annos.equals(other.annos))
            return false;
        if (saltIDs == null) {
            if (other.saltIDs != null)
                return false;
        } else if (!saltIDs.equals(other.saltIDs))
            return false;
        return true;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy