blob: 6e00547c3a7f6e2f2cfba7ed45d9dc6025043bff [file] [log] [blame]
Felix Meschbergere7f513f2012-07-02 14:00:02 +00001/*
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 */
19package org.apache.felix.cm.impl.helper;
20
21
22import org.osgi.framework.Bundle;
23import org.osgi.framework.Constants;
24import org.osgi.framework.ServiceReference;
Felix Meschbergere9502bd2012-07-02 14:57:33 +000025import org.osgi.framework.Version;
Felix Meschbergere7f513f2012-07-02 14:00:02 +000026
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 */
36public 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 Meschberger273985f2012-07-05 12:28:06 +000047 /**
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 Meschbergere7f513f2012-07-02 14:00:02 +000058
Felix Meschbergerc0894f32012-07-04 08:09:55 +000059 /**
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 Meschbergere7f513f2012-07-02 14:00:02 +000079 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 Meschberger273985f2012-07-05 12:28:06 +000089 this.bindingLevel = 0;
Felix Meschbergere7f513f2012-07-02 14:00:02 +000090 }
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 Meschberger273985f2012-07-05 12:28:06 +0000108 this.bindingLevel = 3;
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000109 }
110 else
111 {
112 this.version = rawPid.substring( start );
113 this.location = null;
Felix Meschberger273985f2012-07-05 12:28:06 +0000114 this.bindingLevel = 2;
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000115 }
116 }
117 else
118 {
119 this.symbolicName = rawPid.substring( start );
120 this.version = null;
121 this.location = null;
Felix Meschberger273985f2012-07-05 12:28:06 +0000122 this.bindingLevel = 1;
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000123 }
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 Meschbergere9502bd2012-07-02 14:57:33 +0000149 // already unregistered
150 final Bundle serviceBundle = reference.getBundle();
151 if ( serviceBundle == null )
152 {
153 return false;
154 }
155
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000156 // This is not really targeted
157 if ( this.symbolicName == null )
158 {
159 return true;
160 }
161
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000162 // bundle symbolic names don't match
163 if ( !this.symbolicName.equals( serviceBundle.getSymbolicName() ) )
164 {
165 return false;
166 }
167
Felix Meschbergere9502bd2012-07-02 14:57:33 +0000168 // no more specific target
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000169 if ( this.version == null )
170 {
171 return true;
172 }
Felix Meschbergere9502bd2012-07-02 14:57:33 +0000173
174 // bundle version does not match
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000175
176 if ( !this.version.equals( getBundleVersion( serviceBundle ) ) )
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000177 {
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 Meschberger382a19b2012-07-03 09:45:14 +0000187 * 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 Meschberger273985f2012-07-05 12:28:06 +0000199
Felix Meschberger382a19b2012-07-03 09:45:14 +0000200 /**
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000201 * Returns the service PID of this targeted PID which basically is
202 * the targeted PID without the targeting information.
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000203 */
204 public String getServicePid()
205 {
206 return servicePid;
207 }
208
Felix Meschberger273985f2012-07-05 12:28:06 +0000209
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000210 /**
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000211 * Returns <code>true</code> if this targeted PID binds stronger than
212 * the <code>other</code> {@link TargetedPID}.
Felix Meschberger273985f2012-07-05 12:28:06 +0000213 * <p>
214 * This method assumes both targeted PIDs have already been checked for
215 * suitability for the bundle encoded in the targetting.
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000216 *
Felix Meschberger273985f2012-07-05 12:28:06 +0000217 * @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 Meschbergere7f513f2012-07-02 14:00:02 +0000221 */
Felix Meschberger273985f2012-07-05 12:28:06 +0000222 boolean bindsStronger( final TargetedPID other )
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000223 {
Felix Meschbergercd5195f2012-07-05 17:17:45 +0000224 return this.bindingLevel > other.bindingLevel;
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000225 }
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 Meschberger273985f2012-07-05 12:28:06 +0000240 return false;
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000241 }
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 Meschbergerc0894f32012-07-04 08:09:55 +0000256
Felix Meschberger273985f2012-07-05 12:28:06 +0000257
Felix Meschbergerc0894f32012-07-04 08:09:55 +0000258 @Override
259 public String toString()
260 {
261 return this.rawPid;
262 }
Felix Meschbergere7f513f2012-07-02 14:00:02 +0000263}