diff --git a/libraries.services.yml b/libraries.services.yml
index a5925eb345690b60ae053337bca790acb06dc24d..de969d2e02577b037e5a95d9b535150d4e59849a 100644
--- a/libraries.services.yml
+++ b/libraries.services.yml
@@ -3,12 +3,16 @@ services:
     class: Drupal\libraries\ExternalLibrary\ExternalLibraryManager
     arguments:
       - '@libraries.registry'
+      - '@plugin.manager.libraries.locator'
       - '@libraries.extension_handler'
       - '@libraries.php_file_loader'
   libraries.registry:
     class: Drupal\libraries\ExternalLibrary\Registry\ExternalLibraryRegistry
     # @todo Reconsider the decision to go with JSON instead of YAML.
     arguments: ['@serialization.json']
+  plugin.manager.libraries.locator:
+    class: Drupal\libraries\ExternalLibrary\Local\LocatorManager
+    parent: default_plugin_manager
   libraries.extension_handler:
     class: Drupal\libraries\Extension\ExtensionHandler
     arguments: ['%app.root', '@module_handler', '@theme_handler']
diff --git a/src/Annotation/Locator.php b/src/Annotation/Locator.php
new file mode 100644
index 0000000000000000000000000000000000000000..4cada913a586116bb467deafa1c82a16da53222c
--- /dev/null
+++ b/src/Annotation/Locator.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\Annotation\Locator.
+ */
+
+namespace Drupal\libraries\Annotation;
+
+use Drupal\Component\Annotation\PluginID;
+
+/**
+ * Provides an annotation class for locator plugins.
+ *
+ * @Annotation
+ */
+class Locator extends PluginID {
+
+}
diff --git a/src/ExternalLibrary/Exception/LibraryNotInstalledException.php b/src/ExternalLibrary/Exception/LibraryNotInstalledException.php
index 7fbefb63e9c25af923bf06a99cac0253b237d8b1..ea4486427a9a61ddb2c6f331d77a3c5ab3be659d 100644
--- a/src/ExternalLibrary/Exception/LibraryNotInstalledException.php
+++ b/src/ExternalLibrary/Exception/LibraryNotInstalledException.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\libraries\ExternalLibrary\Exception;
 
-use Drupal\libraries\ExternalLibrary\LocalLibraryInterface;
+use Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface;
 use Drupal\libraries\ExternalLibrary\Utility\LibraryAccessorTrait;
 use Exception;
 
@@ -21,7 +21,7 @@ class LibraryNotInstalledException extends \RuntimeException {
   /**
    * Constructs a library exception.
    *
-   * @param \Drupal\libraries\ExternalLibrary\LocalLibraryInterface $library
+   * @param \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface $library
    *   The library that is not installed.
    * @param string $message
    *   (optional) The exception message.
diff --git a/src/ExternalLibrary/ExternalLibraryManager.php b/src/ExternalLibrary/ExternalLibraryManager.php
index 75f1c17b24c3200f73b95ae480f8941e840ed825..98663c00345005a6326d128df5257d2fbb15600d 100644
--- a/src/ExternalLibrary/ExternalLibraryManager.php
+++ b/src/ExternalLibrary/ExternalLibraryManager.php
@@ -24,6 +24,13 @@ class ExternalLibraryManager implements ExternalLibraryManagerInterface {
    */
   protected $registry;
 
+  /**
+   * The library locator factory.
+   *
+   * @var \Drupal\Component\Plugin\Factory\FactoryInterface
+   */
+  protected $locatorFactory;
+
   /**
    * The extension handler.
    *
@@ -43,6 +50,8 @@ class ExternalLibraryManager implements ExternalLibraryManagerInterface {
    *
    * @param \Drupal\libraries\ExternalLibrary\Registry\ExternalLibraryRegistryInterface $registry
    *   The library registry.
+   * @param \Drupal\Component\Plugin\Factory\FactoryInterface $locator_factory
+   *   The library locator factory.
    * @param \Drupal\libraries\Extension\ExtensionHandlerInterface $extension_handler
    *   The extension handler.
    * @param \Drupal\libraries\ExternalLibrary\PhpFile\PhpFileLoaderInterface $php_file_loader
@@ -50,10 +59,12 @@ class ExternalLibraryManager implements ExternalLibraryManagerInterface {
    */
   public function __construct(
     ExternalLibraryRegistryInterface $registry,
+    FactoryInterface $locator_factory,
     ExtensionHandlerInterface $extension_handler,
     PhpFileLoaderInterface $php_file_loader
   ) {
     $this->registry = $registry;
+    $this->locatorFactory = $locator_factory;
     $this->extensionHandler = $extension_handler;
     $this->phpFileLoader = $php_file_loader;
   }
@@ -62,14 +73,16 @@ class ExternalLibraryManager implements ExternalLibraryManagerInterface {
    * {@inheritdoc}
    */
   public function getRequiredLibraries() {
+    $libraries = [];
     foreach ($this->extensionHandler->getExtensions() as $extension) {
       foreach ($extension->getLibraryDependencies() as $library_id) {
         // Do not bother instantiating a library multiple times.
         if (!isset($libraries[$library_id])) {
-          yield $this->registry->getLibrary($library_id);
+          $libraries[$library_id] = $this->registry->getLibrary($library_id);
         }
       }
     }
+    return $libraries;
   }
 
   /**
@@ -80,9 +93,11 @@ class ExternalLibraryManager implements ExternalLibraryManagerInterface {
     $library = $this->registry->getLibrary($id);
     // @todo Throw an exception instead of silently failing.
     if ($library instanceof PhpFileLibraryInterface) {
-      $path = $library->getLibraryPath();
+      // @todo Somehow make it possible to not repeat this in case the library
+      //   has already been located.
+      $library->getLocator($this->locatorFactory)->locate($library);
       foreach ($library->getPhpFiles() as $file) {
-        $this->phpFileLoader->load($path . '/' . $file);
+        $this->phpFileLoader->load($file);
       }
     }
   }
diff --git a/src/ExternalLibrary/Local/LocalLibraryInterface.php b/src/ExternalLibrary/Local/LocalLibraryInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d4107f5c7c783b42c4d9b7bb888cf4c0411b26a
--- /dev/null
+++ b/src/ExternalLibrary/Local/LocalLibraryInterface.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface.
+ */
+
+namespace Drupal\libraries\ExternalLibrary\Local;
+
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+use Drupal\libraries\ExternalLibrary\ExternalLibraryInterface;
+
+/**
+ * Provides an interface for local libraries.
+ *
+ * Local libraries are libraries that can be found on the filesystem. If the
+ * library files can be found in the filesystem a library is considered
+ * installed and its library path can be retrieved.
+ *
+ * A library not being installed can have a different meaning depending on the
+ * library type. A PHP file library. for example, can not be loaded if it is not
+ * installed whereas an asset library can be loaded from a remote source if one
+ * is provided and that is permitted by the configuration.
+ */
+interface LocalLibraryInterface extends ExternalLibraryInterface {
+
+  /**
+   * Checks whether the library is installed.
+   *
+   * @return bool
+   *   TRUE if the library is installed; FALSE otherwise;
+   */
+  public function isInstalled();
+
+  /**
+   * Marks the library as uninstalled.
+   *
+   * A corresponding method to mark the library as installed is not provided as
+   * an installed library should have a library path, so that
+   * LocalLibraryInterface::setLibraryPath() can be used instead.
+   *
+   * @return $this
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::isInstalled()
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::setLibraryPath()
+   */
+  public function setUninstalled();
+
+  /**
+   * Gets the path to the library.
+   *
+   * @return string
+   *   The absolute path to the library on the filesystem.
+   *
+   * @throws \Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::setLibraryPath()
+   */
+  public function getLibraryPath();
+
+  /**
+   * Sets the library path of the library.
+   *
+   * @param string $path
+   *   The path to the library.
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::getLibraryPath()
+   */
+  public function setLibraryPath($path);
+
+  /**
+   * Gets the locator of this library using the locator factory.
+   *
+   * Because determining the installation status and library path of a library
+   * is not specific to any library or even any library type, this logic is
+   * offloaded to separate locator objects.
+   *
+   * @param \Drupal\Component\Plugin\Factory\FactoryInterface $locator_factory
+   *
+   * @return \Drupal\libraries\ExternalLibrary\Local\LocatorInterface
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocatorInterface
+   */
+  public function getLocator(FactoryInterface $locator_factory);
+
+}
diff --git a/src/ExternalLibrary/Local/LocalLibraryTrait.php b/src/ExternalLibrary/Local/LocalLibraryTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a6de590ec04a6ef6850c1a07ad5cc1899d88f6b
--- /dev/null
+++ b/src/ExternalLibrary/Local/LocalLibraryTrait.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\ExternalLibrary\Local\LocalLibraryTrait.
+ */
+
+namespace Drupal\libraries\ExternalLibrary\Local;
+use Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException;
+
+/**
+ * Provides a trait for local libraries utilizing a stream wrapper.
+ *
+ * It assumes that the library files can be accessed using a specified stream
+ * wrapper and that the first component of the file URIs are the library IDs.
+ * Thus, file URIs are of the form:
+ * stream-wrapper-scheme://library-id/path/to/file/within/the/library/filename
+ *
+ * This trait should only be used by classes implementing LocalLibraryInterface.
+ *
+ * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface
+ */
+trait LocalLibraryTrait {
+
+  /**
+   * Whether or not the library is installed.
+   *
+   * A library being installed means its files can be found on the filesystem.
+   *
+   * @var bool
+   */
+  protected $installed = FALSE;
+
+  /**
+   * The absolute path to the library on the filesystem.
+   *
+   * @var string
+   */
+  protected $libraryPath;
+
+  /**
+   * Checks whether the library is installed.
+   *
+   * @return bool
+   *   TRUE if the library is installed; FALSE otherwise;
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::isInstalled()
+   */
+  public function isInstalled() {
+    return $this->installed;
+  }
+
+  /**
+   * Marks the library as uninstalled.
+   *
+   * A corresponding method to mark the library as installed is not provided as
+   * an installed library should have a library path, so that
+   * LocalLibraryInterface::setLibraryPath() can be used instead.
+   *
+   * @return $this
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::setUninstalled()
+   */
+  public function setUninstalled() {
+    $this->installed = FALSE;
+    return $this;
+  }
+
+  /**
+   * Gets the path to the library.
+   *
+   * @return string
+   *   The absolute path to the library on the filesystem.
+   *
+   * @throws \Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::getLibraryPath()
+   */
+  public function getLibraryPath() {
+    if (!$this->isInstalled()) {
+      /** @var \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface $this */
+      throw new LibraryNotInstalledException($this);
+    }
+
+    return $this->libraryPath;
+  }
+
+  /**
+   * Sets the library path of the library.
+   *
+   * @param string $path
+   *   The path to the library.
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface::getLibraryPath()
+   */
+  public function setLibraryPath($path) {
+    $this->installed = TRUE;
+    $this->libraryPath = (string) $path;
+
+    assert('$this->libraryPath !== ""');
+  }
+
+}
diff --git a/src/ExternalLibrary/Local/LocatorInterface.php b/src/ExternalLibrary/Local/LocatorInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..dbaad0cd898aa956625bee0c0b9413b9d80f0de8
--- /dev/null
+++ b/src/ExternalLibrary/Local/LocatorInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\ExternalLibrary\LocalInterface.
+ */
+
+namespace Drupal\libraries\ExternalLibrary\Local;
+
+use Drupal\libraries\ExternalLibrary\ExternalLibraryInterface;
+
+/**
+ * Provides an interface for library locators.
+ *
+ * Because determining the installation status and library path of a library
+ * is not specific to any library or even any library type, this logic can be
+ * implemented generically in form of a locator.
+ */
+interface LocatorInterface {
+
+  /**
+   * Locates a library.
+   *
+   * @param \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface $library
+   *   The library to locate.
+   */
+  public function locate(LocalLibraryInterface $library);
+
+}
diff --git a/src/ExternalLibrary/Local/LocatorManager.php b/src/ExternalLibrary/Local/LocatorManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..4979f319ba535de849f0f0750e91cc245e01307b
--- /dev/null
+++ b/src/ExternalLibrary/Local/LocatorManager.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\ExternalLibrary\Local\LocatorManager.
+ */
+
+namespace Drupal\libraries\ExternalLibrary\Local;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Provides a plugin manager for library locator plugins.
+ *
+ * @see \Drupal\libraries\ExternalLibrary\Local\LocatorInterface
+ */
+class LocatorManager extends DefaultPluginManager {
+
+  /**
+   * Constructs a locator manager.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/libraries/Locator', $namespaces, $module_handler, 'Drupal\libraries\ExternalLibrary\Local\LocatorInterface', 'Drupal\libraries\Annotation\Locator');
+    $this->alterInfo('libraries_locator_info');
+    $this->setCacheBackend($cache_backend, 'libraries_locator_info');
+  }
+
+}
diff --git a/src/ExternalLibrary/LocalLibraryInterface.php b/src/ExternalLibrary/LocalLibraryInterface.php
deleted file mode 100644
index fc4c997e81dcd5740411e629dd2ba0511a73e561..0000000000000000000000000000000000000000
--- a/src/ExternalLibrary/LocalLibraryInterface.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\libraries\ExternalLibrary\LocalLibraryInterface.
- */
-
-namespace Drupal\libraries\ExternalLibrary;
-
-
-/**
- * Provides an interface for local libraries.
- *
- * @todo Explain
- */
-interface LocalLibraryInterface extends ExternalLibraryInterface {
-
-  /**
-   * Checks whether the library is installed.
-   *
-   * @return bool
-   *   TRUE if the library is installed; FALSE otherwise;
-   */
-  public function isInstalled();
-
-  /**
-   * Gets the path to the library.
-   *
-   * @return string
-   *   The path to the library.
-   *
-   * @throws \Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException
-   */
-  public function getLibraryPath();
-
-}
diff --git a/src/ExternalLibrary/LocalLibraryTrait.php b/src/ExternalLibrary/LocalLibraryTrait.php
deleted file mode 100644
index 7e6249c511570aad3ba468bc2c36fa16a515b616..0000000000000000000000000000000000000000
--- a/src/ExternalLibrary/LocalLibraryTrait.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\libraries\ExternalLibrary\LocalLibraryTrait.
- */
-
-namespace Drupal\libraries\ExternalLibrary;
-
-use Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException;
-
-/**
- * Provides a trait for local libraries utilizing a stream wrapper.
- *
- * It assumes that the library files can be accessed using a specified stream
- * wrapper and that the first component of the file URIs are the library IDs.
- * Thus, file URIs are of the form:
- * stream-wrapper-scheme://library-id/path/to/file/within/the/library/filename
- *
- * This trait should only be used by classes implementing LocalLibraryInterface.
- *
- * @see \Drupal\libraries\ExternalLibrary\LocalLibraryInterface
- */
-trait LocalLibraryTrait {
-
-  /**
-   * The file system helper.
-   *
-   * @var \Drupal\Core\File\FileSystemInterface
-   */
-  protected $fileSystemHelper;
-
-  /**
-   * Checks whether the library is installed.
-   *
-   * @return bool
-   *   TRUE if the library is installed; FALSE otherwise;
-   */
-  public function isInstalled() {
-    return is_dir($this->getLibraryPath()) && is_readable($this->getLibraryPath());
-  }
-
-  /**
-   * Gets the path to the library.
-   *
-   * @return string
-   *   The path to the library.
-   *
-   * @throws \Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException
-   */
-  public function getLibraryPath() {
-    // @todo Validate that the library is installed without causing infinite
-    //   recursion.
-
-    return $this->fileSystemHelper->realpath($this->getUri());
-  }
-
-  /**
-   * Gets the URI of the library.
-   *
-   * @return string
-   *   The URI of the library.
-   */
-  protected function getUri() {
-    /** @var \Drupal\libraries\ExternalLibrary\LocalLibraryInterface|static $this */
-    return $this->getScheme() . '://' . $this->getId();
-  }
-
-  /**
-   * Gets the URI scheme that is used for this type of library.
-   *
-   * @return string
-   *   The URI scheme for this library.
-   */
-  abstract protected function getScheme();
-
-}
diff --git a/src/ExternalLibrary/PhpFile/PhpFileLibrary.php b/src/ExternalLibrary/PhpFile/PhpFileLibrary.php
index 56842b75584bf1e2c528e908532e122955718c3b..48391cc7f0ac904cd3394d95719d14ba5d1490b8 100644
--- a/src/ExternalLibrary/PhpFile/PhpFileLibrary.php
+++ b/src/ExternalLibrary/PhpFile/PhpFileLibrary.php
@@ -6,8 +6,11 @@
  */
 
 namespace Drupal\libraries\ExternalLibrary\PhpFile;
+
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+use Drupal\libraries\ExternalLibrary\Exception\LibraryNotInstalledException;
 use Drupal\libraries\ExternalLibrary\ExternalLibraryTrait;
-use Drupal\libraries\ExternalLibrary\LocalLibraryTrait;
+use Drupal\libraries\ExternalLibrary\Local\LocalLibraryTrait;
 
 /**
  * Provides a base PHP file library implementation.
@@ -17,22 +20,39 @@ class PhpFileLibrary implements PhpFileLibraryInterface {
   use ExternalLibraryTrait;
   use LocalLibraryTrait;
 
+  /**
+   * An array of PHP files for this library.
+   *
+   * @var array
+   */
+  protected $files = [];
+
   /**
    * Constructs a PHP file library.
    *
    * @param string $id
    *   The library ID.
+   * @param array $files
+   *   An array of PHP files for this library.
+   */
+  public function __construct($id, array $files) {
+    $this->id = (string) $id;
+    $this->files = $files;
+  }
+
+  /**
+   * Creates an instance of the library from its definition.
+   *
+   * @param string $id
+   *   The library ID.
    * @param array $definition
    *   The library definition array parsed from the definition JSON file.
    *
-   * @todo Dependency injection
+   * @return static
    */
-  public function __construct($id, array $definition) {
-    $this->id = (string) $id;
-    // @todo Split this into proper properties.
-    $this->definition = $definition;
-
-    $this->fileSystemHelper = \Drupal::service('file_system');
+  public static function create($id, array $definition) {
+    $definition += ['files' => []];
+    return new static($id, $definition['files']);
   }
 
   /**
@@ -46,8 +66,20 @@ class PhpFileLibrary implements PhpFileLibraryInterface {
    * {@inheritdoc}
    */
   public function getPhpFiles() {
-    // @todo
-    return $this->definition['files'];
+    if (!$this->isInstalled()) {
+      throw new LibraryNotInstalledException($this);
+    }
+
+    foreach ($this->files as $file) {
+      yield $this->getLibraryPath() . DIRECTORY_SEPARATOR . $file;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLocator(FactoryInterface $locator_factory) {
+    return $locator_factory->createInstance('stream', ['scheme' => 'php-file']);
   }
 
 }
diff --git a/src/ExternalLibrary/PhpFile/PhpFileLibraryInterface.php b/src/ExternalLibrary/PhpFile/PhpFileLibraryInterface.php
index 8d29fe4839a66507b53dcaf98e91f8be0ab13940..f149a9ff3aca525cac48756df171b90f8bd94484 100644
--- a/src/ExternalLibrary/PhpFile/PhpFileLibraryInterface.php
+++ b/src/ExternalLibrary/PhpFile/PhpFileLibraryInterface.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\libraries\ExternalLibrary\PhpFile;
 
-use Drupal\libraries\ExternalLibrary\LocalLibraryInterface;
+use Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface;
 
 /**
  * Provides an interface for libraries which can be loaded.
@@ -19,7 +19,7 @@ interface PhpFileLibraryInterface extends LocalLibraryInterface {
   /**
    * Returns the PHP files of this library.
    *
-   * @return string[]
+   * @return string[]|\Generator
    *   An array of absolute file paths of PHP files.
    */
   public function getPhpFiles();
diff --git a/src/Plugin/MissingPluginConfigurationException.php b/src/Plugin/MissingPluginConfigurationException.php
new file mode 100644
index 0000000000000000000000000000000000000000..3c0f19bb1f849b4592dcabb1024a98d57172bb93
--- /dev/null
+++ b/src/Plugin/MissingPluginConfigurationException.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\Exception\MissingPluginConfigurationException.
+ */
+
+namespace Drupal\libraries\Plugin;
+use Drupal\Component\Plugin\Exception\PluginException;
+use Exception;
+
+
+/**
+ * Provides an exception class for missing plugin configuration.
+ *
+ * The plugin system allows passing arbitrary data to plugins in form of the
+ * $configuration array. Some plugins, however, may depend on certain keys to
+ * be present in $configuration. This exception class can be used if such keys
+ * are missing.
+ *
+ * @todo Provide accessors for the passed-in information.
+ */
+class MissingPluginConfigurationException extends PluginException {
+
+  /**
+   * Constructs an exception for a missing plugin configuration value.
+   *
+   * @param string $plugin_id
+   *   The plugin ID.
+   * @param $plugin_definition
+   *   The plugin definition
+   * @param array $configuration
+   *   The plugin configuration.
+   * @param $missing_key
+   *   The missing key in the configuration.
+   * @param string $message
+   *   (optional) The exception message.
+   * @param int $code
+   *   (optional) The error code.
+   * @param \Exception $previous
+   *   (optional) The previous exception.
+   */
+  public function __construct(
+    $plugin_id,
+    $plugin_definition,
+    array $configuration,
+    $missing_key,
+    $message = '',
+    $code = 0,
+    \Exception $previous = NULL
+  ) {
+    $message = $message ?: "The '{$missing_key}' key is missing in the configuration of the '{$plugin_id}' plugin.";
+    parent::__construct($message, $code, $previous);
+  }
+
+
+}
+
diff --git a/src/Plugin/libraries/Locator/StreamLocator.php b/src/Plugin/libraries/Locator/StreamLocator.php
new file mode 100644
index 0000000000000000000000000000000000000000..e6a628f60cf90c2f87cc37b76a31ecdbb15dbb25
--- /dev/null
+++ b/src/Plugin/libraries/Locator/StreamLocator.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\libraries\Plugin\libraries\Locator\StreamLocatorTrait.
+ */
+
+namespace Drupal\libraries\Plugin\libraries\Locator;
+
+use Drupal\Component\Plugin\Exception\PluginException;
+use Drupal\Core\File\FileSystemInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface;
+use Drupal\libraries\ExternalLibrary\Local\LocatorInterface;
+use Drupal\libraries\Plugin\MissingPluginConfigurationException;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a locator utilizing a stream wrapper.
+ *
+ * It makes the following assumptions:
+ * - The library files can be accessed using a specified stream.
+ * - The stream wrapper is local (i.e. it returns a proper value in its
+ *   realpath() method).
+ * - The first component of the file URIs are the library IDs (i.e. file URIs
+ *   are of the form: scheme://library-id/path/to/file/filename).
+ *
+ * @Locator("stream")
+ *
+ * @see \Drupal\libraries\ExternalLibrary\Local\LocatorInterface
+ */
+class StreamLocator implements LocatorInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * The file system helper.
+   *
+   * @var \Drupal\Core\File\FileSystemInterface
+   */
+  protected $fileSystemHelper;
+
+  /**
+   * The scheme of the stream wrapper.
+   *
+   * @var string
+   */
+  protected $scheme;
+
+  /**
+   * Constructs a stream locator.
+   *
+   * @param \Drupal\Core\File\FileSystemInterface $file_system_helper
+   *   The file system helper.
+   * @param string $scheme
+   *   The scheme of the stream wrapper.
+   */
+  public function __construct(FileSystemInterface $file_system_helper, $scheme) {
+    $this->fileSystemHelper = $file_system_helper;
+    $this->scheme = (string) $scheme;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    if (!isset($configuration['scheme'])) {
+      throw new MissingPluginConfigurationException($plugin_id, $plugin_definition, $configuration, 'scheme');
+    }
+    return new static($container->get('file_system'), $configuration['scheme']);
+  }
+
+
+  /**
+   * Locates a library.
+   *
+   * @param \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface $library
+   *   The library to locate.
+   *
+   * @see \Drupal\libraries\ExternalLibrary\Local\LocatorInterface::locate()
+   */
+  public function locate(LocalLibraryInterface $library) {
+    $path = $this->fileSystemHelper->realpath($this->getUri($library));
+    if (is_dir($path) && is_readable($path)) {
+      $library->setLibraryPath($path);
+    }
+    else {
+      $library->setUninstalled();
+    }
+  }
+
+  /**
+   * Gets the URI of a library.
+   *
+   * @param \Drupal\libraries\ExternalLibrary\Local\LocalLibraryInterface $library
+   *   The library.
+   *
+   * @return string
+   *   The URI of the library.
+   */
+  protected function getUri(LocalLibraryInterface $library) {
+    return $this->scheme . '://' . $library->getId();
+  }
+
+}