Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
| 18 | */ |
| 19 | package org.apache.felix.cm.impl.helper; |
| 20 | |
| 21 | |
| 22 | import org.osgi.framework.Bundle; |
| 23 | import org.osgi.framework.Constants; |
| 24 | import org.osgi.framework.ServiceReference; |
Felix Meschberger | e9502bd | 2012-07-02 14:57:33 +0000 | [diff] [blame] | 25 | import org.osgi.framework.Version; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 26 | |
| 27 | |
| 28 | /** |
| 29 | * The <code>TargetedPID</code> class represents a targeted PID as read |
| 30 | * from a configuration object. |
| 31 | * <p> |
| 32 | * For a factory configuration the <code>TargetedPID</code> represents |
| 33 | * the factory PID of the configuration. Otherwise it represents the |
| 34 | * PID itself of the configuration. |
| 35 | */ |
| 36 | public class TargetedPID |
| 37 | { |
| 38 | |
| 39 | private final String rawPid; |
| 40 | |
| 41 | private final String servicePid; |
| 42 | |
| 43 | private final String symbolicName; |
| 44 | private final String version; |
| 45 | private final String location; |
| 46 | |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 47 | /** |
| 48 | * The level of binding of this targeted PID: |
| 49 | * <ul> |
| 50 | * <li><code>0</code> -- this PID is not targeted at all</li> |
| 51 | * <li><code>1</code> -- this PID is targeted by the symbolic name</li> |
| 52 | * <li><code>2</code> -- this PID is targeted by the symbolic name and version</li> |
| 53 | * <li><code>3</code> -- this PID is targeted by the symoblic name, version, and location</li> |
| 54 | * </ul> |
| 55 | */ |
| 56 | private final short bindingLevel; |
| 57 | |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 58 | |
Felix Meschberger | c0894f3 | 2012-07-04 08:09:55 +0000 | [diff] [blame] | 59 | /** |
| 60 | * Returns the bundle's version as required for targeted PIDs: If the |
| 61 | * bundle has a version the string representation of the version |
| 62 | * string converted to a Version object is returned. Otherwise the |
| 63 | * string representation of <code>Version.emptyVersion</code> is |
| 64 | * returned. |
| 65 | * <p> |
| 66 | * To remain compatible with pre-R4.2 (Framework API < 1.5) we cannot |
| 67 | * use the <code>Bundle.getVersion()</code> method. |
| 68 | * |
| 69 | * @param bundle The bundle whose version is to be returned. |
| 70 | */ |
| 71 | public static String getBundleVersion( final Bundle bundle ) |
| 72 | { |
| 73 | Object vHeader = bundle.getHeaders().get( Constants.BUNDLE_VERSION ); |
| 74 | Version version = ( vHeader == null ) ? Version.emptyVersion : new Version( vHeader.toString() ); |
| 75 | return version.toString(); |
| 76 | } |
| 77 | |
| 78 | |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 79 | public TargetedPID( final String rawPid ) |
| 80 | { |
| 81 | this.rawPid = rawPid; |
| 82 | |
| 83 | if ( rawPid.indexOf( '|' ) < 0 ) |
| 84 | { |
| 85 | this.servicePid = rawPid; |
| 86 | this.symbolicName = null; |
| 87 | this.version = null; |
| 88 | this.location = null; |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 89 | this.bindingLevel = 0; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 90 | } |
| 91 | else |
| 92 | { |
| 93 | int start = 0; |
| 94 | int end = rawPid.indexOf( '|' ); |
| 95 | this.servicePid = rawPid.substring( start, end ); |
| 96 | |
| 97 | start = end + 1; |
| 98 | end = rawPid.indexOf( '|', start ); |
| 99 | if ( end >= 0 ) |
| 100 | { |
| 101 | this.symbolicName = rawPid.substring( start, end ); |
| 102 | start = end + 1; |
| 103 | end = rawPid.indexOf( '|', start ); |
| 104 | if ( end >= 0 ) |
| 105 | { |
| 106 | this.version = rawPid.substring( start, end ); |
| 107 | this.location = rawPid.substring( end + 1 ); |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 108 | this.bindingLevel = 3; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 109 | } |
| 110 | else |
| 111 | { |
| 112 | this.version = rawPid.substring( start ); |
| 113 | this.location = null; |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 114 | this.bindingLevel = 2; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 115 | } |
| 116 | } |
| 117 | else |
| 118 | { |
| 119 | this.symbolicName = rawPid.substring( start ); |
| 120 | this.version = null; |
| 121 | this.location = null; |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 122 | this.bindingLevel = 1; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | |
| 128 | /** |
| 129 | * Returns true if the target of this PID (bundle symbolic name, |
| 130 | * version, and location) match the bundle registering the referenced |
| 131 | * service. |
| 132 | * <p> |
| 133 | * This method just checks the target not the PID value itself, so |
| 134 | * this method returning <code>true</code> does not indicate whether |
| 135 | * the service actually is registered with a service PID equal to the |
| 136 | * raw PID of this targeted PID. |
| 137 | * <p> |
| 138 | * This method also returns <code>false</code> if the service has |
| 139 | * concurrently been unregistered and the registering bundle is now |
| 140 | * <code>null</code>. |
| 141 | * |
| 142 | * @param reference <code>ServiceReference</code> to the registered |
| 143 | * service |
| 144 | * @return <code>true</code> if the referenced service matches the |
| 145 | * target of this PID. |
| 146 | */ |
| 147 | public boolean matchesTarget( ServiceReference<?> reference ) |
| 148 | { |
Felix Meschberger | e9502bd | 2012-07-02 14:57:33 +0000 | [diff] [blame] | 149 | // already unregistered |
| 150 | final Bundle serviceBundle = reference.getBundle(); |
| 151 | if ( serviceBundle == null ) |
| 152 | { |
| 153 | return false; |
| 154 | } |
| 155 | |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 156 | // This is not really targeted |
| 157 | if ( this.symbolicName == null ) |
| 158 | { |
| 159 | return true; |
| 160 | } |
| 161 | |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 162 | // bundle symbolic names don't match |
| 163 | if ( !this.symbolicName.equals( serviceBundle.getSymbolicName() ) ) |
| 164 | { |
| 165 | return false; |
| 166 | } |
| 167 | |
Felix Meschberger | e9502bd | 2012-07-02 14:57:33 +0000 | [diff] [blame] | 168 | // no more specific target |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 169 | if ( this.version == null ) |
| 170 | { |
| 171 | return true; |
| 172 | } |
Felix Meschberger | e9502bd | 2012-07-02 14:57:33 +0000 | [diff] [blame] | 173 | |
| 174 | // bundle version does not match |
Felix Meschberger | c0894f3 | 2012-07-04 08:09:55 +0000 | [diff] [blame] | 175 | |
| 176 | if ( !this.version.equals( getBundleVersion( serviceBundle ) ) ) |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 177 | { |
| 178 | return false; |
| 179 | } |
| 180 | |
| 181 | // assert bundle location match |
| 182 | return this.location == null || this.location.equals( serviceBundle.getLocation() ); |
| 183 | } |
| 184 | |
| 185 | |
| 186 | /** |
Felix Meschberger | 382a19b | 2012-07-03 09:45:14 +0000 | [diff] [blame] | 187 | * Gets the raw PID with which this instance has been created. |
| 188 | * <p> |
| 189 | * If an actual service PID contains pipe symbols that PID might be |
| 190 | * considered being targeted PID without it actually being one. This |
| 191 | * method provides access to the raw PID to allow for such services to |
| 192 | * be configured. |
| 193 | */ |
| 194 | public String getRawPid() |
| 195 | { |
| 196 | return rawPid; |
| 197 | } |
| 198 | |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 199 | |
Felix Meschberger | 382a19b | 2012-07-03 09:45:14 +0000 | [diff] [blame] | 200 | /** |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 201 | * Returns the service PID of this targeted PID which basically is |
| 202 | * the targeted PID without the targeting information. |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 203 | */ |
| 204 | public String getServicePid() |
| 205 | { |
| 206 | return servicePid; |
| 207 | } |
| 208 | |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 209 | |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 210 | /** |
Felix Meschberger | cd5195f | 2012-07-05 17:17:45 +0000 | [diff] [blame^] | 211 | * Returns <code>true</code> if this targeted PID binds stronger than |
| 212 | * the <code>other</code> {@link TargetedPID}. |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 213 | * <p> |
| 214 | * This method assumes both targeted PIDs have already been checked for |
| 215 | * suitability for the bundle encoded in the targetting. |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 216 | * |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 217 | * @param other The targeted PID to check whether it is binding stronger |
| 218 | * or not. |
| 219 | * @return <code>true</code> if the <code>other</code> targeted PID |
| 220 | * is binding strong. |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 221 | */ |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 222 | boolean bindsStronger( final TargetedPID other ) |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 223 | { |
Felix Meschberger | cd5195f | 2012-07-05 17:17:45 +0000 | [diff] [blame^] | 224 | return this.bindingLevel > other.bindingLevel; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 225 | } |
| 226 | |
| 227 | |
| 228 | @Override |
| 229 | public int hashCode() |
| 230 | { |
| 231 | return this.rawPid.hashCode(); |
| 232 | } |
| 233 | |
| 234 | |
| 235 | @Override |
| 236 | public boolean equals( Object obj ) |
| 237 | { |
| 238 | if ( obj == null ) |
| 239 | { |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 240 | return false; |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 241 | } |
| 242 | else if ( obj == this ) |
| 243 | { |
| 244 | return true; |
| 245 | } |
| 246 | |
| 247 | // assume equality if same class and raw PID equals |
| 248 | if ( this.getClass() == obj.getClass() ) |
| 249 | { |
| 250 | return this.rawPid.equals( ( ( TargetedPID ) obj ).rawPid ); |
| 251 | } |
| 252 | |
| 253 | // not the same class or different raw PID |
| 254 | return false; |
| 255 | } |
Felix Meschberger | c0894f3 | 2012-07-04 08:09:55 +0000 | [diff] [blame] | 256 | |
Felix Meschberger | 273985f | 2012-07-05 12:28:06 +0000 | [diff] [blame] | 257 | |
Felix Meschberger | c0894f3 | 2012-07-04 08:09:55 +0000 | [diff] [blame] | 258 | @Override |
| 259 | public String toString() |
| 260 | { |
| 261 | return this.rawPid; |
| 262 | } |
Felix Meschberger | e7f513f | 2012-07-02 14:00:02 +0000 | [diff] [blame] | 263 | } |