Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgRepository.java @ 490:b3c16d1aede0
Refactoring: move HgRepository's implementation aspects to Internals (which is now its imlementation counterpart and primary repository class to be used by other parts of the library)
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 16 Aug 2012 17:08:34 +0200 |
| parents | 45b3b6ca046f |
| children | 4a670f76e7d1 |
comparison
equal
deleted
inserted
replaced
| 489:9c0138cda59a | 490:b3c16d1aede0 |
|---|---|
| 32 | 32 |
| 33 import org.tmatesoft.hg.core.Nodeid; | 33 import org.tmatesoft.hg.core.Nodeid; |
| 34 import org.tmatesoft.hg.core.SessionContext; | 34 import org.tmatesoft.hg.core.SessionContext; |
| 35 import org.tmatesoft.hg.internal.ByteArrayChannel; | 35 import org.tmatesoft.hg.internal.ByteArrayChannel; |
| 36 import org.tmatesoft.hg.internal.ConfigFile; | 36 import org.tmatesoft.hg.internal.ConfigFile; |
| 37 import org.tmatesoft.hg.internal.DataAccessProvider; | |
| 38 import org.tmatesoft.hg.internal.Experimental; | 37 import org.tmatesoft.hg.internal.Experimental; |
| 39 import org.tmatesoft.hg.internal.Filter; | 38 import org.tmatesoft.hg.internal.Filter; |
| 40 import org.tmatesoft.hg.internal.Internals; | 39 import org.tmatesoft.hg.internal.Internals; |
| 41 import org.tmatesoft.hg.internal.RevlogStream; | 40 import org.tmatesoft.hg.internal.RevlogStream; |
| 42 import org.tmatesoft.hg.internal.SubrepoManager; | 41 import org.tmatesoft.hg.internal.SubrepoManager; |
| 52 * Shall be as state-less as possible, all the caching happens outside the repo, in commands/walkers | 51 * Shall be as state-less as possible, all the caching happens outside the repo, in commands/walkers |
| 53 * | 52 * |
| 54 * @author Artem Tikhomirov | 53 * @author Artem Tikhomirov |
| 55 * @author TMate Software Ltd. | 54 * @author TMate Software Ltd. |
| 56 */ | 55 */ |
| 57 public final class HgRepository { | 56 public final class HgRepository implements SessionContext.Source { |
| 58 | 57 |
| 59 // IMPORTANT: if new constants added, consider fixing HgInternals#wrongRevisionIndex and HgInvalidRevisionException#getMessage | 58 // IMPORTANT: if new constants added, consider fixing HgInternals#wrongRevisionIndex and HgInvalidRevisionException#getMessage |
| 60 | 59 |
| 61 /** | 60 /** |
| 62 * Revision index constant to indicate most recent revision | 61 * Revision index constant to indicate most recent revision |
| 98 } | 97 } |
| 99 | 98 |
| 100 private final File repoDir; // .hg folder | 99 private final File repoDir; // .hg folder |
| 101 private final File workingDir; // .hg/../ | 100 private final File workingDir; // .hg/../ |
| 102 private final String repoLocation; | 101 private final String repoLocation; |
| 103 private final DataAccessProvider dataAccess; | |
| 104 private final PathRewrite normalizePath; // normalized slashes but otherwise regular file names | 102 private final PathRewrite normalizePath; // normalized slashes but otherwise regular file names |
| 105 private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled | 103 private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled |
| 106 private final PathRewrite repoPathHelper; // access to system files | 104 private final PathRewrite repoPathHelper; // access to system files |
| 107 private final SessionContext sessionContext; | 105 private final SessionContext sessionContext; |
| 108 | 106 |
| 131 | 129 |
| 132 HgRepository(String repositoryPath) { | 130 HgRepository(String repositoryPath) { |
| 133 repoDir = null; | 131 repoDir = null; |
| 134 workingDir = null; | 132 workingDir = null; |
| 135 repoLocation = repositoryPath; | 133 repoLocation = repositoryPath; |
| 136 dataAccess = null; | |
| 137 dataPathHelper = repoPathHelper = null; | 134 dataPathHelper = repoPathHelper = null; |
| 138 normalizePath = null; | 135 normalizePath = null; |
| 139 sessionContext = null; | 136 sessionContext = null; |
| 140 impl = null; | 137 impl = null; |
| 141 } | 138 } |
| 151 repoDir = repositoryRoot; | 148 repoDir = repositoryRoot; |
| 152 workingDir = repoDir.getParentFile(); | 149 workingDir = repoDir.getParentFile(); |
| 153 if (workingDir == null) { | 150 if (workingDir == null) { |
| 154 throw new IllegalArgumentException(repoDir.toString()); | 151 throw new IllegalArgumentException(repoDir.toString()); |
| 155 } | 152 } |
| 156 impl = new org.tmatesoft.hg.internal.Internals(ctx); | |
| 157 repoLocation = repositoryPath; | 153 repoLocation = repositoryPath; |
| 158 sessionContext = ctx; | 154 sessionContext = ctx; |
| 159 dataAccess = new DataAccessProvider(ctx); | 155 impl = new org.tmatesoft.hg.internal.Internals(this, repositoryRoot); |
| 160 impl.parseRequires(this, new File(repoDir, "requires")); | 156 impl.parseRequires(); |
| 161 normalizePath = impl.buildNormalizePathRewrite(); | 157 normalizePath = impl.buildNormalizePathRewrite(); |
| 162 dataPathHelper = impl.buildDataFilesHelper(); | 158 dataPathHelper = impl.buildDataFilesHelper(); |
| 163 repoPathHelper = impl.buildRepositoryFilesHelper(); | 159 repoPathHelper = impl.buildRepositoryFilesHelper(); |
| 164 } | 160 } |
| 165 | 161 |
| 171 public String getLocation() { | 167 public String getLocation() { |
| 172 return repoLocation; | 168 return repoLocation; |
| 173 } | 169 } |
| 174 | 170 |
| 175 public boolean isInvalid() { | 171 public boolean isInvalid() { |
| 176 return repoDir == null || !repoDir.exists() || !repoDir.isDirectory(); | 172 return impl == null || impl.isInvalid(); |
| 177 } | 173 } |
| 178 | 174 |
| 179 public HgChangelog getChangelog() { | 175 public HgChangelog getChangelog() { |
| 180 if (changelog == null) { | 176 if (changelog == null) { |
| 181 CharSequence storagePath = repoPathHelper.rewrite("00changelog.i"); | 177 CharSequence storagePath = repoPathHelper.rewrite("00changelog.i"); |
| 208 hgTags.content(i, sink); | 204 hgTags.content(i, sink); |
| 209 final String content = new String(sink.toArray(), "UTF8"); | 205 final String content = new String(sink.toArray(), "UTF8"); |
| 210 tags.readGlobal(new StringReader(content)); | 206 tags.readGlobal(new StringReader(content)); |
| 211 } catch (CancelledException ex) { | 207 } catch (CancelledException ex) { |
| 212 // IGNORE, can't happen, we did not configure cancellation | 208 // IGNORE, can't happen, we did not configure cancellation |
| 213 getContext().getLog().dump(getClass(), Debug, ex, null); | 209 getSessionContext().getLog().dump(getClass(), Debug, ex, null); |
| 214 } catch (IOException ex) { | 210 } catch (IOException ex) { |
| 215 // UnsupportedEncodingException can't happen (UTF8) | 211 // UnsupportedEncodingException can't happen (UTF8) |
| 216 // only from readGlobal. Need to reconsider exceptions thrown from there: | 212 // only from readGlobal. Need to reconsider exceptions thrown from there: |
| 217 // BufferedReader wraps String and unlikely to throw IOException, perhaps, log is enough? | 213 // BufferedReader wraps String and unlikely to throw IOException, perhaps, log is enough? |
| 218 getContext().getLog().dump(getClass(), Error, ex, null); | 214 getSessionContext().getLog().dump(getClass(), Error, ex, null); |
| 219 // XXX need to decide what to do this. failure to read single revision shall not break complete cycle | 215 // XXX need to decide what to do this. failure to read single revision shall not break complete cycle |
| 220 } | 216 } |
| 221 } | 217 } |
| 222 } | 218 } |
| 223 File file2read = null; | 219 File file2read = null; |
| 224 try { | 220 try { |
| 225 file2read = new File(getWorkingDir(), HgTags.getPath()); | 221 file2read = new File(getWorkingDir(), HgTags.getPath()); |
| 226 tags.readGlobal(file2read); // XXX replace with HgDataFile.workingCopy | 222 tags.readGlobal(file2read); // XXX replace with HgDataFile.workingCopy |
| 227 file2read = new File(repoDir, HgLocalTags.getName()); | 223 file2read = impl.getFileFromRepoDir(HgLocalTags.getName()); // XXX pass internalrepo to readLocal, keep filename there |
| 228 tags.readLocal(file2read); | 224 tags.readLocal(file2read); |
| 229 } catch (IOException ex) { | 225 } catch (IOException ex) { |
| 230 getContext().getLog().dump(getClass(), Error, ex, null); | 226 getSessionContext().getLog().dump(getClass(), Error, ex, null); |
| 231 throw new HgInvalidControlFileException("Failed to read tags", ex, file2read); | 227 throw new HgInvalidControlFileException("Failed to read tags", ex, file2read); |
| 232 } | 228 } |
| 233 } | 229 } |
| 234 return tags; | 230 return tags; |
| 235 } | 231 } |
| 239 * @return branch manager instance, never <code>null</code> | 235 * @return branch manager instance, never <code>null</code> |
| 240 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | 236 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
| 241 */ | 237 */ |
| 242 public HgBranches getBranches() throws HgInvalidControlFileException { | 238 public HgBranches getBranches() throws HgInvalidControlFileException { |
| 243 if (branches == null) { | 239 if (branches == null) { |
| 244 branches = new HgBranches(this); | 240 branches = new HgBranches(impl); |
| 245 branches.collect(ProgressSupport.Factory.get(null)); | 241 branches.collect(ProgressSupport.Factory.get(null)); |
| 246 } | 242 } |
| 247 return branches; | 243 return branches; |
| 248 } | 244 } |
| 249 | 245 |
| 251 * Access state of the recent merge | 247 * Access state of the recent merge |
| 252 * @return merge state facility, never <code>null</code> | 248 * @return merge state facility, never <code>null</code> |
| 253 */ | 249 */ |
| 254 public HgMergeState getMergeState() { | 250 public HgMergeState getMergeState() { |
| 255 if (mergeState == null) { | 251 if (mergeState == null) { |
| 256 mergeState = new HgMergeState(this); | 252 mergeState = new HgMergeState(impl); |
| 257 } | 253 } |
| 258 return mergeState; | 254 return mergeState; |
| 259 } | 255 } |
| 260 | 256 |
| 261 public HgDataFile getFileNode(String path) { | 257 public HgDataFile getFileNode(String path) { |
| 287 /** | 283 /** |
| 288 * @return pair of values, {@link Pair#first()} and {@link Pair#second()} are respective parents, never <code>null</code>. | 284 * @return pair of values, {@link Pair#first()} and {@link Pair#second()} are respective parents, never <code>null</code>. |
| 289 * @throws HgInvalidControlFileException if attempt to read information about working copy parents from dirstate failed | 285 * @throws HgInvalidControlFileException if attempt to read information about working copy parents from dirstate failed |
| 290 */ | 286 */ |
| 291 public Pair<Nodeid,Nodeid> getWorkingCopyParents() throws HgInvalidControlFileException { | 287 public Pair<Nodeid,Nodeid> getWorkingCopyParents() throws HgInvalidControlFileException { |
| 292 return HgDirstate.readParents(this, new File(repoDir, Dirstate.getName())); | 288 return HgDirstate.readParents(impl); |
| 293 } | 289 } |
| 294 | 290 |
| 295 /** | 291 /** |
| 296 * @return name of the branch associated with working directory, never <code>null</code>. | 292 * @return name of the branch associated with working directory, never <code>null</code>. |
| 297 * @throws HgInvalidControlFileException if attempt to read branch name failed. | 293 * @throws HgInvalidControlFileException if attempt to read branch name failed. |
| 298 */ | 294 */ |
| 299 public String getWorkingCopyBranchName() throws HgInvalidControlFileException { | 295 public String getWorkingCopyBranchName() throws HgInvalidControlFileException { |
| 300 if (wcBranch == null) { | 296 if (wcBranch == null) { |
| 301 wcBranch = HgDirstate.readBranch(this, new File(repoDir, "branch")); | 297 wcBranch = HgDirstate.readBranch(impl); |
| 302 } | 298 } |
| 303 return wcBranch; | 299 return wcBranch; |
| 304 } | 300 } |
| 305 | 301 |
| 306 /** | 302 /** |
| 326 | 322 |
| 327 | 323 |
| 328 public HgRepoConfig getConfiguration() /* XXX throws HgInvalidControlFileException? Description of the exception suggests it is only for files under ./hg/*/ { | 324 public HgRepoConfig getConfiguration() /* XXX throws HgInvalidControlFileException? Description of the exception suggests it is only for files under ./hg/*/ { |
| 329 if (repoConfig == null) { | 325 if (repoConfig == null) { |
| 330 try { | 326 try { |
| 331 ConfigFile configFile = impl.readConfiguration(this, getRepositoryRoot()); | 327 ConfigFile configFile = impl.readConfiguration(); |
| 332 repoConfig = new HgRepoConfig(configFile); | 328 repoConfig = new HgRepoConfig(configFile); |
| 333 } catch (IOException ex) { | 329 } catch (IOException ex) { |
| 334 String m = "Errors while reading user configuration file"; | 330 String m = "Errors while reading user configuration file"; |
| 335 getContext().getLog().dump(getClass(), Warn, ex, m); | 331 getSessionContext().getLog().dump(getClass(), Warn, ex, m); |
| 336 return new HgRepoConfig(new ConfigFile(getContext())); // empty config, do not cache, allow to try once again | 332 return new HgRepoConfig(new ConfigFile(getSessionContext())); // empty config, do not cache, allow to try once again |
| 337 //throw new HgInvalidControlFileException(m, ex, null); | 333 //throw new HgInvalidControlFileException(m, ex, null); |
| 338 } | 334 } |
| 339 } | 335 } |
| 340 return repoConfig; | 336 return repoConfig; |
| 341 } | 337 } |
| 360 public CharSequence rewrite(CharSequence path) { | 356 public CharSequence rewrite(CharSequence path) { |
| 361 return path.toString().toLowerCase(); | 357 return path.toString().toLowerCase(); |
| 362 } | 358 } |
| 363 }; | 359 }; |
| 364 } | 360 } |
| 365 File dirstateFile = new File(repoDir, Dirstate.getName()); | 361 HgDirstate ds = new HgDirstate(impl, pathFactory, canonicalPath); |
| 366 HgDirstate ds = new HgDirstate(this, dirstateFile, pathFactory, canonicalPath); | 362 ds.read(); |
| 367 ds.read(impl.buildFileNameEncodingHelper()); | |
| 368 return ds; | 363 return ds; |
| 369 } | 364 } |
| 370 | 365 |
| 371 /** | 366 /** |
| 372 * Access to configured set of ignored files. | 367 * Access to configured set of ignored files. |
| 379 ignore = new HgIgnore(getToRepoPathHelper()); | 374 ignore = new HgIgnore(getToRepoPathHelper()); |
| 380 File ignoreFile = new File(getWorkingDir(), HgIgnore.getPath()); | 375 File ignoreFile = new File(getWorkingDir(), HgIgnore.getPath()); |
| 381 try { | 376 try { |
| 382 final List<String> errors = ignore.read(ignoreFile); | 377 final List<String> errors = ignore.read(ignoreFile); |
| 383 if (errors != null) { | 378 if (errors != null) { |
| 384 getContext().getLog().dump(getClass(), Warn, "Syntax errors parsing %s:\n%s", ignoreFile.getName(), Internals.join(errors, ",\n")); | 379 getSessionContext().getLog().dump(getClass(), Warn, "Syntax errors parsing %s:\n%s", ignoreFile.getName(), Internals.join(errors, ",\n")); |
| 385 } | 380 } |
| 386 } catch (IOException ex) { | 381 } catch (IOException ex) { |
| 387 final String m = String.format("Error reading %s file", ignoreFile); | 382 final String m = String.format("Error reading %s file", ignoreFile); |
| 388 throw new HgInvalidControlFileException(m, ex, ignoreFile); | 383 throw new HgInvalidControlFileException(m, ex, ignoreFile); |
| 389 } | 384 } |
| 397 * | 392 * |
| 398 * @return message used for last commit attempt, or <code>null</code> if none | 393 * @return message used for last commit attempt, or <code>null</code> if none |
| 399 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | 394 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
| 400 */ | 395 */ |
| 401 public String getCommitLastMessage() throws HgInvalidControlFileException { | 396 public String getCommitLastMessage() throws HgInvalidControlFileException { |
| 402 File lastMessage = new File(repoDir, LastMessage.getPath()); | 397 File lastMessage = impl.getFileFromRepoDir(LastMessage.getPath()); |
| 403 if (!lastMessage.canRead()) { | 398 if (!lastMessage.canRead()) { |
| 404 return null; | 399 return null; |
| 405 } | 400 } |
| 406 FileReader fr = null; | 401 FileReader fr = null; |
| 407 try { | 402 try { |
| 414 } finally { | 409 } finally { |
| 415 if (fr != null) { | 410 if (fr != null) { |
| 416 try { | 411 try { |
| 417 fr.close(); | 412 fr.close(); |
| 418 } catch (IOException ex) { | 413 } catch (IOException ex) { |
| 419 getContext().getLog().dump(getClass(), Warn, "Failed to close %s after read", lastMessage); | 414 getSessionContext().getLog().dump(getClass(), Warn, "Failed to close %s after read", lastMessage); |
| 420 } | 415 } |
| 421 } | 416 } |
| 422 } | 417 } |
| 423 } | 418 } |
| 424 | 419 |
| 437 */ | 432 */ |
| 438 @Experimental(reason="WORK IN PROGRESS") | 433 @Experimental(reason="WORK IN PROGRESS") |
| 439 public HgRepositoryLock getWorkingDirLock() { | 434 public HgRepositoryLock getWorkingDirLock() { |
| 440 if (wdLock == null) { | 435 if (wdLock == null) { |
| 441 int timeout = getLockTimeout(); | 436 int timeout = getLockTimeout(); |
| 442 File lf = new File(getRepositoryRoot(), "wlock"); | 437 File lf = impl.getFileFromRepoDir("wlock"); |
| 443 synchronized (this) { | 438 synchronized (this) { |
| 444 if (wdLock == null) { | 439 if (wdLock == null) { |
| 445 wdLock = new HgRepositoryLock(lf, timeout); | 440 wdLock = new HgRepositoryLock(lf, timeout); |
| 446 } | 441 } |
| 447 } | 442 } |
| 451 | 446 |
| 452 @Experimental(reason="WORK IN PROGRESS") | 447 @Experimental(reason="WORK IN PROGRESS") |
| 453 public HgRepositoryLock getStoreLock() { | 448 public HgRepositoryLock getStoreLock() { |
| 454 if (storeLock == null) { | 449 if (storeLock == null) { |
| 455 int timeout = getLockTimeout(); | 450 int timeout = getLockTimeout(); |
| 456 File fl = new File(getRepositoryRoot(), repoPathHelper.rewrite("lock").toString()); | 451 File fl = impl.getFileFromRepoDir(repoPathHelper.rewrite("lock").toString()); |
| 457 synchronized (this) { | 452 synchronized (this) { |
| 458 if (storeLock == null) { | 453 if (storeLock == null) { |
| 459 storeLock = new HgRepositoryLock(fl, timeout); | 454 storeLock = new HgRepositoryLock(fl, timeout); |
| 460 } | 455 } |
| 461 } | 456 } |
| 468 * @return facility to manage bookmarks, never <code>null</code> | 463 * @return facility to manage bookmarks, never <code>null</code> |
| 469 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | 464 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
| 470 */ | 465 */ |
| 471 public HgBookmarks getBookmarks() throws HgInvalidControlFileException { | 466 public HgBookmarks getBookmarks() throws HgInvalidControlFileException { |
| 472 if (bookmarks == null) { | 467 if (bookmarks == null) { |
| 473 bookmarks = new HgBookmarks(this); | 468 bookmarks = new HgBookmarks(impl); |
| 474 bookmarks.read(); | 469 bookmarks.read(); |
| 475 } | 470 } |
| 476 return bookmarks; | 471 return bookmarks; |
| 477 } | 472 } |
| 478 | 473 |
| 479 /*package-local*/ DataAccessProvider getDataAccess() { | 474 /** |
| 480 return dataAccess; | 475 * @return session environment of the repository |
| 476 */ | |
| 477 public SessionContext getSessionContext() { | |
| 478 return sessionContext; | |
| 481 } | 479 } |
| 482 | 480 |
| 483 /** | 481 /** |
| 484 * Perhaps, should be separate interface, like ContentLookup | 482 * Perhaps, should be separate interface, like ContentLookup |
| 485 * path - repository storage path (i.e. one usually with .i or .d) | 483 * path - repository storage path (i.e. one usually with .i or .d) |
| 490 if (cached != null) { | 488 if (cached != null) { |
| 491 return cached; | 489 return cached; |
| 492 } | 490 } |
| 493 File f = new File(repoDir, path.toString()); | 491 File f = new File(repoDir, path.toString()); |
| 494 if (f.exists()) { | 492 if (f.exists()) { |
| 495 RevlogStream s = new RevlogStream(dataAccess, f); | 493 RevlogStream s = new RevlogStream(impl.getDataAccess(), f); |
| 496 if (impl.shallCacheRevlogs()) { | 494 if (impl.shallCacheRevlogs()) { |
| 497 streamsCache.put(path, new SoftReference<RevlogStream>(s)); | 495 streamsCache.put(path, new SoftReference<RevlogStream>(s)); |
| 498 } | 496 } |
| 499 return s; | 497 return s; |
| 500 } else { | 498 } else { |
| 501 if (shallFakeNonExistent) { | 499 if (shallFakeNonExistent) { |
| 502 try { | 500 try { |
| 503 File fake = File.createTempFile(f.getName(), null); | 501 File fake = File.createTempFile(f.getName(), null); |
| 504 fake.deleteOnExit(); | 502 fake.deleteOnExit(); |
| 505 return new RevlogStream(dataAccess, fake); | 503 return new RevlogStream(impl.getDataAccess(), fake); |
| 506 } catch (IOException ex) { | 504 } catch (IOException ex) { |
| 507 getContext().getLog().dump(getClass(), Info, ex, null); | 505 getSessionContext().getLog().dump(getClass(), Info, ex, null); |
| 508 } | 506 } |
| 509 } | 507 } |
| 510 } | 508 } |
| 511 return null; // XXX empty stream instead? | 509 return null; // XXX empty stream instead? |
| 512 } | 510 } |
| 521 | 519 |
| 522 /*package-local*/ File getFile(HgDataFile dataFile) { | 520 /*package-local*/ File getFile(HgDataFile dataFile) { |
| 523 return new File(getWorkingDir(), dataFile.getPath().toString()); | 521 return new File(getWorkingDir(), dataFile.getPath().toString()); |
| 524 } | 522 } |
| 525 | 523 |
| 526 /*package-local*/ SessionContext getContext() { | |
| 527 return sessionContext; | |
| 528 } | |
| 529 | |
| 530 /*package-local*/ Internals getImplHelper() { | 524 /*package-local*/ Internals getImplHelper() { |
| 531 return impl; | 525 return impl; |
| 532 } | 526 } |
| 533 | 527 |
| 534 private List<Filter> instantiateFilters(Path p, Filter.Options opts) { | 528 private List<Filter> instantiateFilters(Path p, Filter.Options opts) { |
| 535 List<Filter.Factory> factories = impl.getFilters(this); | 529 List<Filter.Factory> factories = impl.getFilters(); |
| 536 if (factories.isEmpty()) { | 530 if (factories.isEmpty()) { |
| 537 return Collections.emptyList(); | 531 return Collections.emptyList(); |
| 538 } | 532 } |
| 539 ArrayList<Filter> rv = new ArrayList<Filter>(factories.size()); | 533 ArrayList<Filter> rv = new ArrayList<Filter>(factories.size()); |
| 540 for (Filter.Factory ff : factories) { | 534 for (Filter.Factory ff : factories) { |
