##### Coverage Report - org.apache.commons.configuration.JNDIConfiguration

Classes in this File | Line Coverage | Branch Coverage | Complexity

JNDIConfiguration

88% | 87/99

85% | 17/20

2.736842105263158;2,737

1

     /*

2

      * Licensed to the Apache Software Foundation (ASF) under one or more

3

      * contributor license agreements.  See the NOTICE file distributed with

4

      * this work for additional information regarding copyright ownership.

5

      * The ASF licenses this file to You under the Apache License, Version 2.0

6

      * (the "License"); you may not use this file except in compliance with

7

      * the License.  You may obtain a copy of the License at

8

      *

9

      *     http://www.apache.org/licenses/LICENSE-2.0

10

      *

11

      * Unless required by applicable law or agreed to in writing, software

12

      * distributed under the License is distributed on an "AS IS" BASIS,

13

      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

14

      * See the License for the specific language governing permissions and

15

      * limitations under the License.

16

      */

17

18

     package org.apache.commons.configuration;

19

20

     import java.util.ArrayList;

21

     import java.util.HashSet;

22

     import java.util.Iterator;

23

     import java.util.List;

24

     import java.util.Set;

25

26

     import javax.naming.Context;

27

     import javax.naming.InitialContext;

28

     import javax.naming.NameClassPair;

29

     import javax.naming.NameNotFoundException;

30

     import javax.naming.NamingEnumeration;

31

     import javax.naming.NamingException;

32

33

     import org.apache.commons.lang.StringUtils;

34

     import org.apache.commons.logging.Log;

35

     import org.apache.commons.logging.LogFactory;

36

37

     /**

38

      * This Configuration class allows you to interface with a JNDI datasource.

39

      * A JNDIConfiguration is read-only, write operations will throw an

40

      * UnsupportedOperationException. The clear operations are supported but the

41

      * underlying JNDI data source is not changed.

42

      *

43

      * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>

44

      * @version $Id: JNDIConfiguration.java 439648 2006-09-02 20:42:10Z oheger $

45

      */

46

10

     public class JNDIConfiguration extends AbstractConfiguration

47

     {

48

         /** Logger. */

49

10

         private static Log log = LogFactory.getLog(JNDIConfiguration.class);

50

51

         /** The prefix of the context. */

52

         private String prefix;

53

54

         /** The initial JNDI context. */

55

         private Context context;

56

57

         /** The base JNDI context. */

58

         private Context baseContext;

59

60

         /** The Set of keys that have been virtually cleared. */

61

49

         private Set clearedProperties = new HashSet();

62

63

         /**

64

          * Creates a JNDIConfiguration using the default initial context as the

65

          * root of the properties.

66

          *

67

          * @throws NamingException thrown if an error occurs when initializing the default context

68

          */

69

         public JNDIConfiguration() throws NamingException

70

         {

71

47

             this((String) null);

72

47

         }

73

74

         /**

75

          * Creates a JNDIConfiguration using the default initial context, shifted

76

          * with the specified prefix, as the root of the properties.

77

          *

78

          * @param prefix the prefix

79

          *

80

          * @throws NamingException thrown if an error occurs when initializing the default context

81

          */

82

         public JNDIConfiguration(String prefix) throws NamingException

83

         {

84

47

             this(new InitialContext(), prefix);

85

47

         }

86

87

         /**

88

          * Creates a JNDIConfiguration using the specified initial context as the

89

          * root of the properties.

90

          *

91

          * @param context the initial context

92

          */

93

         public JNDIConfiguration(Context context)

94

         {

95

1

             this(context, null);

96

1

         }

97

98

         /**

99

          * Creates a JNDIConfiguration using the specified initial context shifted

100

          * by the specified prefix as the root of the properties.

101

          *

102

          * @param context the initial context

103

          * @param prefix the prefix

104

          */

105

         public JNDIConfiguration(Context context, String prefix)

106

49

         {

107

49

             this.context = context;

108

49

             this.prefix = prefix;

109

49

         }

110

111

         /**

112

          * This method recursive traverse the JNDI tree, looking for Context objects.

113

          * When it finds them, it traverses them as well.  Otherwise it just adds the

114

          * values to the list of keys found.

115

          *

116

          * @param keys All the keys that have been found.

117

          * @param context The parent context

118

          * @param prefix What prefix we are building on.

119

          * @throws NamingException If JNDI has an issue.

120

          */

121

         private void recursiveGetKeys(Set keys, Context context, String prefix) throws NamingException

122

         {

123

11

             NamingEnumeration elements = null;

124

125

             try

126

             {

127

11

                 elements = context.list("");

128

129

                 // iterates through the context's elements

130

96

                 while (elements.hasMore())

131

                 {

132

74

                     NameClassPair nameClassPair = (NameClassPair) elements.next();

133

74

                     String name = nameClassPair.getName();

134

74

                     Object object = context.lookup(name);

135

136

                     // build the key

137

74

                     StringBuffer key = new StringBuffer();

138

74

                     key.append(prefix);

139

74

                     if (key.length() > 0)

140

                     {

141

70

                         key.append(".");

142

                     }

143

74

                     key.append(name);

144

145

74

                     if (object instanceof Context)

146

                     {

147

                         // add the keys of the sub context

148

4

                         Context subcontext = (Context) object;

149

4

                         recursiveGetKeys(keys, subcontext, key.toString());

150

                     }

151

                     else

152

                     {

153

                         // add the key

154

70

                         keys.add(key.toString());

155

                     }

156

                 }

157

11

             }

158

             finally

159

             {

160

                 // close the enumeration

161

0

                 if (elements != null)

162

                 {

163

11

                     elements.close();

164

                 }

165

             }

166

11

         }

167

168

         /**

169

          * Returns an iterator with all property keys stored in this configuration.

170

          *

171

          * @return an iterator with all keys

172

          */

173

         public Iterator getKeys()

174

         {

175

4

             return getKeys("");

176

         }

177

178

         /**

179

          * Returns an iterator with all property keys starting with the given

180

          * prefix.

181

          *

182

          * @param prefix the prefix

183

          * @return an iterator with the selected keys

184

          */

185

         public Iterator getKeys(String prefix)

186

         {

187

             // build the path

188

11

             String[] splitPath = StringUtils.split(prefix, ".");

189

190

11

             List path = new ArrayList();

191

192

22

             for (int i = 0; i < splitPath.length; i++)

193

             {

194

11

                 path.add(splitPath[i]);

195

             }

196

197

             try

198

             {

199

                 // find the context matching the specified path

200

11

                 Context context = getContext(path, getBaseContext());

201

202

                 // return all the keys under the context found

203

11

                 Set keys = new HashSet();

204

11

                 if (context != null)

205

                 {

206

7

                     recursiveGetKeys(keys, context, prefix);

207

                 }

208

4

                 else if (containsKey(prefix))

209

                 {

210

                     // add the prefix if it matches exactly a property key

211

2

                     keys.add(prefix);

212

                 }

213

214

11

                 return keys.iterator();

215

             }

216

             catch (NamingException e)

217

             {

218

0

                 log.error(e.getMessage(), e);

219

0

                 return new ArrayList().iterator();

220

             }

221

         }

222

223

         /**

224

          * Because JNDI is based on a tree configuration, we need to filter down the

225

          * tree, till we find the Context specified by the key to start from.

226

          * Otherwise return null.

227

          *

228

          * @param path     the path of keys to traverse in order to find the context

229

          * @param context  the context to start from

230

          * @return The context at that key's location in the JNDI tree, or null if not found

231

          * @throws NamingException if JNDI has an issue

232

          */

233

         private Context getContext(List path, Context context) throws NamingException

234

         {

235

             // return the current context if the path is empty

236

16

             if (path == null || path.isEmpty())

237

             {

238

7

                 return context;

239

             }

240

241

9

             String key = (String) path.get(0);

242

243

             // search a context matching the key in the context's elements

244

9

             NamingEnumeration elements = null;

245

246

             try

247

             {

248

9

                 elements = context.list("");

249

40

                 while (elements.hasMore())

250

                 {

251

27

                     NameClassPair nameClassPair = (NameClassPair) elements.next();

252

27

                     String name = nameClassPair.getName();

253

27

                     Object object = context.lookup(name);

254

255

27

                     if (object instanceof Context && name.equals(key))

256

                     {

257

5

                         Context subcontext = (Context) object;

258

259

                         // recursive search in the sub context

260

5

                         return getContext(path.subList(1, path.size()), subcontext);

261

                     }

262

                 }

263

4

             }

264

             finally

265

             {

266

0

                 if (elements != null)

267

                 {

268

9

                     elements.close();

269

                 }

270

             }

271

272

4

             return null;

273

         }

274

275

         /**

276

          * Returns a flag whether this configuration is empty.

277

          *

278

          * @return the empty flag

279

          */

280

         public boolean isEmpty()

281

         {

282

             try

283

             {

284

2

                 NamingEnumeration enumeration = null;

285

286

                 try

287

                 {

288

2

                     enumeration = getBaseContext().list("");

289

2

                     return !enumeration.hasMore();

290

                 }

291

                 finally

292

                 {

293

                     // close the enumeration

294

0

                     if (enumeration != null)

295

                     {

296

2

                         enumeration.close();

297

                     }

298

                 }

299

             }

300

             catch (NamingException e)

301

             {

302

0

                 log.error(e.getMessage(), e);

303

0

                 return true;

304

             }

305

         }

306

307

         /**

308

          * <p><strong>This operation is not supported and will throw an

309

          * UnsupportedOperationException.</strong></p>

310

          *

311

          * @param key the key

312

          * @param value the value

313

          * @throws UnsupportedOperationException

314

          */

315

         public void setProperty(String key, Object value)

316

         {

317

0

             throw new UnsupportedOperationException("This operation is not supported");

318

         }

319

320

         /**

321

          * Removes the specified property.

322

          *

323

          * @param key the key of the property to remove

324

          */

325

         public void clearProperty(String key)

326

         {

327

4

             clearedProperties.add(key);

328

4

         }

329

330

         /**

331

          * Checks whether the specified key is contained in this configuration.

332

          *

333

          * @param key the key to check

334

          * @return a flag whether this key is stored in this configuration

335

          */

336

         public boolean containsKey(String key)

337

         {

338

10

             if (clearedProperties.contains(key))

339

             {

340

1

                 return false;

341

             }

342

9

             key = StringUtils.replace(key, ".", "/");

343

             try

344

             {

345

                 // throws a NamingException if JNDI doesn't contain the key.

346

9

                 getBaseContext().lookup(key);

347

5

                 return true;

348

             }

349

             catch (NameNotFoundException e)

350

             {

351

                 // expected exception, no need to log it

352

4

                 return false;

353

             }

354

             catch (NamingException e)

355

             {

356

0

                 log.error(e.getMessage(), e);

357

0

                 return false;

358

             }

359

         }

360

361

         /**

362

          * Returns the prefix.

363

          * @return the prefix

364

          */

365

         public String getPrefix()

366

         {

367

0

             return prefix;

368

         }

369

370

         /**

371

          * Sets the prefix.

372

          *

373

          * @param prefix The prefix to set

374

          */

375

         public void setPrefix(String prefix)

376

         {

377

3

             this.prefix = prefix;

378

379

             // clear the previous baseContext

380

3

             baseContext = null;

381

3

         }

382

383

         /**

384

          * Returns the value of the specified property.

385

          *

386

          * @param key the key of the property

387

          * @return the value of this property

388

          */

389

         public Object getProperty(String key)

390

         {

391

69

             if (clearedProperties.contains(key))

392

             {

393

3

                 return null;

394

             }

395

396

             try

397

             {

398

66

                 key = StringUtils.replace(key, ".", "/");

399

66

                 return getBaseContext().lookup(key);

400

             }

401

             catch (NameNotFoundException e)

402

             {

403

                 // expected exception, no need to log it

404

7

                 return null;

405

             }

406

             catch (NamingException e)

407

             {

408

7

                 log.error(e.getMessage(), e);

409

7

                 return null;

410

             }

411

         }

412

413

         /**

414

          * <p><strong>This operation is not supported and will throw an

415

          * UnsupportedOperationException.</strong></p>

416

          *

417

          * @param key the key

418

          * @param obj the value

419

          * @throws UnsupportedOperationException

420

          */

421

         protected void addPropertyDirect(String key, Object obj)

422

         {

423

0

             throw new UnsupportedOperationException("This operation is not supported");

424

         }

425

426

         /**

427

          * Return the base context with the prefix applied.

428

          *

429

          * @return the base context

430

          * @throws NamingException if an error occurs

431

          */

432

         public Context getBaseContext() throws NamingException

433

         {

434

88

             if (baseContext == null)

435

             {

436

47

                 baseContext = (Context) getContext().lookup(prefix == null ? "" : prefix);

437

             }

438

439

88

             return baseContext;

440

         }

441

442

         /**

443

          * Return the initial context used by this configuration. This context is

444

          * independent of the prefix specified.

445

          *

446

          * @return the initial context

447

          */

448

         public Context getContext()

449

         {

450

47

             return context;

451

         }

452

453

         /**

454

          * Set the initial context of the configuration.

455

          *

456

          * @param context the context

457

          */

458

         public void setContext(Context context)

459

         {

460

             // forget the removed properties

461

1

             clearedProperties.clear();

462

463

             // change the context

464

1

             this.context = context;

465

1

         }

466

     }