blob: 124f46d496f9fe4818a30562989c27f4f984fe82 [file] [log] [blame]
/*
* 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;
}
}