/* * Copyright (C) 2015 The Android Open Source Project * * 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 com.android.statementservice.retriever; import android.annotation.NonNull; import java.util.regex.Pattern; /** * An immutable value type representing a statement relation with "kind" and "detail". * * <p> The set of kinds is enumerated by the API: <ul> <li> <b>delegate_permission</b>: The detail * field specifies which permission to delegate. A statement involving this relation does not * constitute a requirement to do the delegation, just a permission to do so. </ul> * * <p> We may add other kinds in the future. * * <p> The detail field is a lowercase alphanumeric string with underscores and periods allowed * (matching the regex [a-z0-9_.]+), but otherwise unstructured. */ public final class Relation { private static final Pattern KIND_PATTERN = Pattern.compile("^[a-z0-9_.]+$"); private static final Pattern DETAIL_PATTERN = Pattern.compile("^([a-z0-9_.]+)$"); private final String mKind; private final String mDetail; private Relation(String kind, String detail) { mKind = kind; mDetail = detail; } /** * Returns the relation's kind. */ @NonNull public String getKind() { return mKind; } /** * Returns the relation's detail. */ @NonNull public String getDetail() { return mDetail; } /** * Creates a new Relation object for the specified {@code kind} and {@code detail}. * * @throws AssociationServiceException if {@code kind} or {@code detail} is not well formatted. */ public static Relation create(@NonNull String kind, @NonNull String detail) throws AssociationServiceException { if (!KIND_PATTERN.matcher(kind).matches() || !DETAIL_PATTERN.matcher(detail).matches()) { throw new AssociationServiceException("Relation not well formatted."); } return new Relation(kind, detail); } /** * Creates a new Relation object from its string representation. * * @throws AssociationServiceException if the relation is not well formatted. */ public static Relation create(@NonNull String relation) throws AssociationServiceException { String[] r = relation.split("/", 2); if (r.length != 2) { throw new AssociationServiceException("Relation not well formatted."); } return create(r[0], r[1]); } /** * Returns true if {@code relation} has the same kind and detail. */ public boolean matches(Relation relation) { return getKind().equals(relation.getKind()) && getDetail().equals(relation.getDetail()); } /** * Returns a string representation of this relation. */ @Override public String toString() { StringBuilder relation = new StringBuilder(); relation.append(getKind()); relation.append("/"); relation.append(getDetail()); return relation.toString(); } // equals() and hashCode() are generated by Android Studio. @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Relation relation = (Relation) o; if (mDetail != null ? !mDetail.equals(relation.mDetail) : relation.mDetail != null) { return false; } if (mKind != null ? !mKind.equals(relation.mKind) : relation.mKind != null) { return false; } return true; } @Override public int hashCode() { int result = mKind != null ? mKind.hashCode() : 0; result = 31 * result + (mDetail != null ? mDetail.hashCode() : 0); return result; } }