--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/java/smf-old/org/opensolaris/os/scf/common/FMRI.java Thu Jan 19 16:01:30 2012 -0500
@@ -0,0 +1,432 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package org.opensolaris.os.scf.common;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.beans.ConstructorProperties;
+import java.util.Map;
+import java.util.EnumMap;
+import javax.management.openmbean.*;
+
+/**
+ * A basic FMRI class. Probably should be named "SmfFMRI", as
+ * legacy-run services aren't an SCF concept.
+ */
+public class FMRI implements Comparable<FMRI>, CompositeDataView
+{
+ /*
+ * Static data
+ */
+ public static final String SCF_SCOPE_LOCAL = "localhost";
+ private static final String FORMAT =
+ "([A-Za-z][_A-Za-z0-9.-]*,)?[_A-Za-z0-9-]*";
+ private static final Map<FMRIScheme, String> scheme_strings =
+ new EnumMap<FMRIScheme, String>(FMRIScheme.class);
+
+ static {
+ scheme_strings.put(FMRIScheme.FILE, "file");
+ scheme_strings.put(FMRIScheme.LEGACY, "lrc");
+ scheme_strings.put(FMRIScheme.SERVICE, "svc");
+ }
+
+ /*
+ * FMRI components
+ */
+ private FMRIScheme scheme_;
+ private String scope_ = null;
+ private String service_ = null;
+ private String instance_ = null;
+ private String pg_ = null;
+ private String property_ = null;
+ private String name_ = null;
+
+ /*
+ * Derivative information
+ */
+ private FMRIType svctype_;
+ private String canonicalStr_;
+
+ /**
+ * Creates an FMRI from a URI.
+ */
+ public FMRI(URI uri) throws URISyntaxException
+ {
+ if (!uri.isAbsolute() || uri.isOpaque())
+ throw (new URISyntaxException(uri.toString(),
+ "Bad FMRI"));
+
+ String scheme = uri.getScheme();
+ scope_ = uri.getAuthority();
+ if (scope_ == null || scope_.isEmpty() ||
+ scope_.equals(SCF_SCOPE_LOCAL))
+ scope_ = null;
+ canonicalStr_ = new URI(uri.getScheme(), scope_, uri.getPath(),
+ null, null).toString();
+
+ if (scheme.equals("svc")) {
+ scheme_ = FMRIScheme.SERVICE;
+ svctype_ = FMRIType.SCOPE;
+
+ String[] top = uri.getPath().split("/:properties/", 2);
+
+ String[] next = top[0].split(":", 2);
+ /*
+ * We can assume the path starts with a slash
+ * because we reject relative URIs above.
+ */
+ service_ = next[0].substring(1);
+ svctype_ = FMRIType.SERVICE;
+ if (next.length == 2) {
+ instance_ = next[1];
+ if (!instance_.matches(FORMAT))
+ throw (new URISyntaxException(
+ uri.toString(),
+ "Invalid instance: " + instance_));
+ svctype_ = FMRIType.INSTANCE;
+ }
+
+ if (top.length == 2) {
+ next = top[1].split("/", 2);
+ pg_ = next[0];
+ if (!pg_.matches(FORMAT))
+ throw (new URISyntaxException(
+ uri.toString(),
+ "Invalid property group: " + pg_));
+ svctype_ = FMRIType.PGROUP;
+ if (next.length == 2) {
+ property_ = next[1];
+ if (!property_.matches(FORMAT))
+ throw (new URISyntaxException(
+ uri.toString(),
+ "Invalid property: " +
+ property_));
+ svctype_ = FMRIType.PROPERTY;
+ }
+ }
+ } else if (scheme.equals("file")) {
+ scheme_ = FMRIScheme.FILE;
+ name_ = uri.getPath();
+ } else if (scheme.equals("lrc")) {
+ scheme_ = FMRIScheme.LEGACY;
+ name_ = uri.getPath();
+ } else {
+ throw (new URISyntaxException(uri.toString(),
+ "Invalid FMRI scheme: " + scheme));
+ }
+ }
+
+ /**
+ * Creates an FMRI from a string.
+ */
+ public FMRI(String fmri) throws URISyntaxException
+ {
+ /* Work around bug 6504439 in scf_scope_to_fmri */
+ this(new URI(fmri.equals("svc:") ? "svc:///" : fmri));
+ }
+
+ /**
+ * Constucts an FMRI from its attributes. Needed for the class to be
+ * reconstructable.
+ */
+ @SuppressWarnings({"fallthrough"})
+ @ConstructorProperties({"scheme", "svcType", "scope", "name", "service",
+ "instance", "propertyGroup", "property"})
+ public FMRI(FMRIScheme scheme, FMRIType type, String scope, String name,
+ String service, String instance, String pg, String property)
+ {
+ scheme_ = scheme;
+
+ scope_ = scope;
+ if (scope_ == null || scope_.isEmpty() ||
+ scope_.equals(SCF_SCOPE_LOCAL))
+ scope_ = null;
+
+ String path;
+ if (scheme != FMRIScheme.SERVICE) {
+ svctype_ = FMRIType.NONE;
+ path = name_ = name;
+ } else {
+ svctype_ = type;
+ name_ = null;
+
+ path = "";
+ switch (svctype_) {
+ case PROPERTY:
+ property_ = property;
+ path = "/" + property + path;
+ case PGROUP:
+ pg_ = pg;
+ path = "/:properties/" + pg + path;
+ case INSTANCE:
+ instance_ = instance;
+ path = ":" + instance + path;
+ case SERVICE:
+ service_ = service;
+ path = "/" + service + path;
+ }
+ }
+
+ try {
+ URI uri = new URI(scheme_strings.get(scheme), scope_,
+ path, null, null);
+ canonicalStr_ = uri.toString();
+ } catch (URISyntaxException ex) {
+ canonicalStr_ = null;
+ }
+ }
+
+ /**
+ * Returns the FMRI's type (scheme).
+ */
+ public FMRIScheme getScheme()
+ {
+ return (scheme_);
+ }
+
+ /**
+ * Returns a svc: FMRI's type.
+ */
+ public FMRIType getSvcType()
+ {
+ if (scheme_ != FMRIScheme.SERVICE)
+ throw (new FMRIException(this, "not a service FMRI"));
+ return (svctype_);
+ }
+
+ /**
+ * Returns the FMRI's scope.
+ */
+ public String getScope()
+ {
+ return (scope_ == null ? SCF_SCOPE_LOCAL : scope_);
+ }
+
+ /**
+ * Returns the name of a legacy-run or file FMRI.
+ */
+ public String getName()
+ {
+ if (scheme_ == FMRIScheme.SERVICE)
+ throw (new FMRIException(this,
+ "not a file or legacy FMRI"));
+ return (name_);
+ }
+
+ /**
+ * Throws an FMRIException from a function which may only be
+ * called on a svc: FMRI. Takes the FMRIType required by the
+ * caller.
+ */
+ private void checktype(FMRIType svctype)
+ {
+ String prefix = "unable to read " + svctype;
+ if (scheme_ != FMRIScheme.SERVICE)
+ throw (new FMRIException(this, prefix +
+ " from non-service FMRI"));
+ if (svctype_.compareTo(svctype) < 0)
+ throw (new FMRIException(this, prefix +
+ " from " + svctype_ + "FMRI"));
+ }
+
+ /**
+ * Returns the service component of a service FMRI.
+ */
+ public String getService()
+ {
+ checktype(FMRIType.SERVICE);
+ return (service_);
+ }
+
+ /**
+ * Returns the instance component of a service FMRI, or {@code
+ * null} if there is none.
+ */
+ public String getInstance()
+ {
+ checktype(FMRIType.INSTANCE);
+ return (instance_);
+ }
+
+ /**
+ * Returns the property group component of a service FMRI.
+ */
+ public String getPropertyGroup()
+ {
+ checktype(FMRIType.PGROUP);
+ return (pg_);
+ }
+
+ /**
+ * Returns the property component of a service FMRI.
+ */
+ public String getProperty()
+ {
+ checktype(FMRIType.PROPERTY);
+ return (property_);
+ }
+
+ public FMRI toServiceFMRI()
+ {
+ checktype(FMRIType.SERVICE);
+ if (svctype_ == FMRIType.SERVICE)
+ return this;
+ return (new FMRI(scheme_, FMRIType.SERVICE, scope_, null,
+ service_, null, null, null));
+ }
+
+ public FMRI toInstanceFMRI()
+ {
+ checktype(FMRIType.INSTANCE);
+ if (svctype_ == FMRIType.INSTANCE)
+ return this;
+ return (new FMRI(scheme_, FMRIType.INSTANCE, scope_, null,
+ service_, instance_, null, null));
+ }
+
+ public FMRI toInstanceFMRI(String instanceName)
+ {
+ checktype(FMRIType.SERVICE);
+ return (new FMRI(scheme_, FMRIType.INSTANCE, scope_, null,
+ service_, instanceName, null, null));
+ }
+
+
+ /*
+ * CompositeDataView methods
+ */
+
+ private static final String[] itemNames = new String[] { "scheme",
+ "svcType", "scope", "name", "service", "instance", "propertyGroup",
+ "property" };
+
+ /*
+ * Manually convert the FMRI to its automatically-determined
+ * CompositeType. This conversion is normally performed by the
+ * MXBean implementation, but the automatic conversion uses our
+ * accessors to inspect the object. Performing the conversion
+ * manually permits us to circumvent the run-time checking
+ * performed by our accessors (or to put it differently, permits
+ * us to leave the run-time checking in place).
+ */
+ public CompositeData toCompositeData(CompositeType ct)
+ {
+ Object[] itemValues = new Object[] { scheme_.name(),
+ svctype_.name(), scope_, name_, service_, instance_, pg_,
+ property_ };
+ try {
+ return (new CompositeDataSupport(ct, itemNames,
+ itemValues));
+ } catch (OpenDataException ex) {
+ throw (new RuntimeException(ex));
+ }
+ }
+
+ // Comparable methods
+
+ private static int strcmp(String a, String b)
+ {
+ if (a == null)
+ return (b == null ? 0 : 1);
+ if (b == null)
+ return (-1);
+ return (a.compareTo(b));
+ }
+
+ public int compareTo(FMRI f)
+ {
+ int result = scheme_.compareTo(f.scheme_);
+
+ if (result == 0)
+ result = strcmp(scope_, f.scope_);
+ if (scheme_ != FMRIScheme.SERVICE)
+ result = strcmp(name_, f.name_);
+ else {
+ if (result == 0)
+ result = strcmp(service_, f.service_);
+ if (result == 0)
+ result = strcmp(instance_, f.instance_);
+ if (result == 0)
+ result = strcmp(pg_, f.pg_);
+ if (result == 0)
+ result = strcmp(property_, f.property_);
+ }
+
+ return (result);
+ }
+
+ /*
+ * Object methods
+ */
+
+ /**
+ * Returns the FMRI as a string.
+ */
+ @Override
+ public String toString()
+ {
+ return (canonicalStr_);
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o == null)
+ return (false);
+
+ FMRI f;
+ try {
+ f = (FMRI)o;
+ } catch (ClassCastException e) {
+ return (false);
+ }
+
+ return (compareTo(f) == 0);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = 7;
+ hash = 79 * hash +
+ (this.scope_ != null ? this.scope_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.service_ != null ? this.service_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.instance_ != null ? this.instance_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.pg_ != null ? this.pg_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.property_ != null ? this.property_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.name_ != null ? this.name_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.scheme_ != null ? this.scheme_.hashCode() : 0);
+ hash = 79 * hash +
+ (this.svctype_ != null ? this.svctype_.hashCode() : 0);
+ return hash;
+ }
+}