diff --git a/config/config-template.php b/config/config-template.php
index baaf2b4eb9fb9102c4a62398efe795145af143ea..3da780acd732ffd8fdec8a156855dbecb85e577a 100644
--- a/config/config-template.php
+++ b/config/config-template.php
@@ -140,14 +140,42 @@ $config = array (
 
 
 	/*
-	 * Meta data handler.
+	 * This option configures the metadata sources. The metadata sources is given as an array with
+	 * different metadata sources. When searching for metadata, simpleSAMPphp will search through
+	 * the array from start to end.
 	 *
-	 *	Options: [flatfile,saml2xmlmeta]
+	 * Each element in the array is an associative array which configures the metadata source.
+	 * The type of the metadata source is given by the 'type' element. For each type we have
+	 * different configuration options.
 	 *
+	 * Flat file metadata handler:
+	 * - 'type': This is always 'flatfile'.
+	 * - 'directory': The directory we will load the metadata files from. The default value for
+	 *                this option is the value of the 'metadatadir' configuration option, or
+	 *                'metadata/' if that option is unset.
+	 *
+	 *
+	 * Examples:
+	 *
+	 * This example defines two flatfile sources. One is the default metadata directory, the other
+	 * is a metadata directory with autogenerated metadata files.
+	 *
+	 * 'metadata.sources' => array(
+	 *     array('type' => 'flatfile'),
+	 *     array('type' => 'flatfile', 'directory' => 'metadata-generated'),
+	 *     ),
+	 *
+	 *
+	 * Default:
+	 * 'metadata.sources' => array(
+	 *     array('type' => 'flatfile')
+	 *     ),
 	 */
-	'metadata.handler'		=> 'flatfile',
+	'metadata.sources' => array(
+		array('type' => 'flatfile'),
+		),
+
 
-	
 	/*
 	 * LDAP configuration. This is only relevant if you use the LDAP authentication plugin.
 	 */
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
index 001aecd91e2c55e4773503d827d9be786ef2f26d..03074e5c1193ca5074078783b6b2550ecfe23b7e 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
@@ -1,107 +1,95 @@
 <?php
 
 require_once('SimpleSAML/Configuration.php');
-require_once('SimpleSAML/Utilities.php');
+require_once('SimpleSAML/Metadata/MetaDataStorageSource.php');
 
 /**
- * This file defines a base class for metadata handling.
- * Instantiation of session handler objects should be done through
- * the class method getMetadataHandler().
+ * This file defines a class for metadata handling.
  *
  * @author Andreas Åkre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
  * @package simpleSAMLphp
  * @version $Id$
  */ 
-abstract class SimpleSAML_Metadata_MetaDataStorageHandler {
+class SimpleSAML_Metadata_MetaDataStorageHandler {
 
 
-	protected $metadata = null;
-	protected $hostmap = null;
-
-
-	/* This static variable contains a reference to the current
+	/**
+	 * This static variable contains a reference to the current
 	 * instance of the metadata handler. This variable will be NULL if
 	 * we haven't instantiated a metadata handler yet.
 	 */
 	private static $metadataHandler = NULL;
 
 
+	/**
+	 * This is a list of all the metadata sources we have in our metadata
+	 * chain. When we need metadata, we will look through this chain from start to end.
+	 */
+	private $sources;
 
-	/* This function retrieves the current instance of the metadata handler.
+
+	/**
+	 * This function retrieves the current instance of the metadata handler.
 	 * The metadata handler will be instantiated if this is the first call
 	 * to this fuunction.
 	 *
-	 * Returns:
-	 *  The current metadata handler.
+	 * @return The current metadata handler instance.
 	 */
 	public static function getMetadataHandler() {
 		if(self::$metadataHandler === NULL) {
-			self::createMetadataHandler();
+			self::$metadataHandler = new SimpleSAML_Metadata_MetaDataStorageHandler();
 		}
 
 		return self::$metadataHandler;
 	}
 
 
-
-	/* This constructor is included in case it is needed in the the
-	 * future. Including it now allows us to write parent::__construct() in
-	 * the subclasses of this class.
+	/**
+	 * This constructor initializes this metadata storage handler. It will load and
+	 * parse the configuration, and initialize the metadata source list.
 	 */
 	protected function __construct() {
-		
-	}
-
 
-	/* This function creates an instance of the metadata handler which is
-	 * selected in the 'metadata.handler' configuration directive. If no
-	 * metadata handler is selected, then we will fall back to the default
-	 * PHP metadata handler.
-	 */
-	public static function createMetadataHandler() {
-	
-		/* Get the configuration. */
 		$config = SimpleSAML_Configuration::getInstance();
-		assert($config instanceof SimpleSAML_Configuration);
 
-		/* Get the metadata handler option from the configuration. */
-		$handler = $config->getValue('metadata.handler');
+		$sourcesConfig = $config->getValue('metadata.sources', NULL);
 
-		/* If 'session.handler' is NULL or unset, then we want
-		 * to fall back to the default PHP session handler.
-		 */
-		if(is_null($handler)) {
-			$handler = 'flatfile';
+		/* For backwards compatibility, and to provide a default configuration. */
+		if($sourcesConfig === NULL) {
+			$type = $config->getValue('metadata.handler', 'flatfile');
+			$sourcesConfig = array(array('type' => $type));
 		}
 
-
-		/* The session handler must be a string. */
-		if(!is_string($handler)) {
-			throw new Exception('Invalid setting for the [metadata.handler] configuration option. This option should be set to a valid string.');
+		if(!is_array($sourcesConfig)) {
+			throw new Exception(
+				'Invalid configuration of the \'metadata.sources\' configuration option.' .
+				' This option should be an array.'
+				);
 		}
 
-		$handler = strtolower($handler);
-
-		if($handler === 'flatfile') {
+		$this->sources = array();
 		
-			require_once('SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php');
-			$sh = new SimpleSAML_Metadata_MetaDataStorageHandlerFlatfile();
-			
-		} elseif ($handler === 'saml2xmlmeta')  {
-
-			require_once('SimpleSAML/Metadata/MetaDataStorageHandlerSAML2Meta.php');
-			$sh = new SimpleSAML_Metadata_MetaDataStorageHandlerSAML2Meta();
+		foreach($sourcesConfig as $elementConfig) {
+			if(!is_array($elementConfig)) {
+				throw new Exception(
+					'Invalid configuration of the \'metadata.sources\' configuration option.' .
+					' Every element in the array should be an associative array.'
+					);
+			}
 
-		
-		} else {
-			throw new Exception('Invalid value for the [metadata.handler] configuration option. Unknown handler: ' . $handler);
+			$src = SimpleSAML_Metadata_MetaDataStorageSource::getSource($elementConfig);
+			$this->sources[] = $src;
 		}
-		
-		/* Set the session handler. */
-		self::$metadataHandler = $sh;
 	}
-	
-	
+
+
+	/**
+	 * This function is used to generate some metadata elements automatically.
+	 *
+	 * @param $property  The metadata property which should be autogenerated.
+	 * @param $set  The set we the property comes from.
+	 * @return The autogenerated metadata property.
+	 */
 	public function getGenerated($property, $set = 'saml20-sp-hosted') {
 		
 		/* Get the configuration. */
@@ -146,49 +134,116 @@ abstract class SimpleSAML_Metadata_MetaDataStorageHandler {
 		
 		throw new Exception('Could not generate metadata property ' . $property . ' for set ' . $set . '.');
 	}
-	
+
+
+	/**
+	 * This function lists all known metadata in the given set. It is returned as an associative array
+	 * where the key is the entity id.
+	 *
+	 * @param $set  The set we want to list metadata from.
+	 * @return An associative array with the metadata from from the given set.
+	 */
 	public function getList($set = 'saml20-idp-remote') {
-		if (!isset($this->metadata[$set])) {
-			$this->load($set);
+
+		assert('is_string($set)');
+
+		$result = array();
+
+		foreach($this->sources as $source) {
+			$srcList = $source->getMetadataSet($set);
+
+			/* $result is the last argument to array_merge because we want the content already
+			 * in $result to have precedence.
+			 */
+			$result = array_merge($srcList, $result);
 		}
-		return $this->metadata[$set];
+
+		return $result;
 	}
-	
+
+
+	/**
+	 * This function retrieves metadata for the current entity based on the hostname/path the request
+	 * was directed to. It will throw an exception if it is unable to locate the metadata.
+	 *
+	 * @param $set  The set we want metadata from.
+	 * @return An associative array with the metadata.
+	 */
 	public function getMetaDataCurrent($set = 'saml20-sp-hosted') {
-		return $this->getMetaData($this->getMetaDataCurrentEntityID($set), $set);
+		return $this->getMetaData(NULL, $set);
 	}
-	
+
+
+	/**
+	 * This function locates the current entity id based on the hostname/path combination the user accessed.
+	 * It will throw an exception if it is unable to locate the entity id.
+	 *
+	 * @param $set  The set we look for the entity id in.
+	 * @return The entity id which is associated with the current hostname/path combination.
+	 */
 	public function getMetaDataCurrentEntityID($set = 'saml20-sp-hosted') {
+
+		assert('is_string($set)');
+
+		/* First we look for the hostname/path combination. */
+		$currenthostwithpath = SimpleSAML_Utilities::getSelfHostWithPath(); // sp.example.org/university
+
+		foreach($this->sources as $source) {
+			$entityId = $source->getEntityIdFromHostPath($currenthostwithpath, $set);
+			if($entityId !== NULL) {
+				return $entityId;
+			}
+		}
+
 	
-		if (!isset($this->metadata[$set])) {
-			$this->load($set);
+		/* Then we look for the hostname. */
+		$currenthost = SimpleSAML_Utilities::getSelfHost(); // sp.example.org
+		if(strpos($currenthost, ":") !== FALSE) {
+			$currenthostdecomposed = explode(":", $currenthost);
+			$currenthost = $currenthostdecomposed[0];
 		}
-		$currenthost         = SimpleSAML_Utilities::getSelfHost(); 			// sp.example.org
-		$currenthostwithpath = SimpleSAML_Utilities::getSelfHostWithPath(); 	// sp.example.org/university
-		
-		if(strstr($currenthost, ":")) {
-				$currenthostdecomposed = explode(":", $currenthost);
-				$currenthost = $currenthostdecomposed[0];
+
+		foreach($this->sources as $source) {
+			$entityId = $source->getEntityIdFromHostPath($currenthost, $set);
+			if($entityId !== NULL) {
+				return $entityId;
+			}
 		}
-		
-		if (!isset($this->hostmap[$set])) {
-			throw new Exception('No default entities defined for metadata set [' . $set . '] (host:' . $currenthost. ')');
+
+
+		/* We were unable to find the hostname/path in any metadata source. */
+		throw new Exception('Could not find any default metadata entities in set [' . $set . '] for host [' . $currenthost . ' : ' . $currenthostwithpath . ']');
+	}
+
+
+	/**
+	 * This function looks up the metadata for the given entity id in the given set. It will throw an
+	 * exception if it is unable to locate the metadata.
+	 *
+	 * @param $entityId  The entity id we are looking up. This parameter may be NULL, in which case we look up
+	 *                   the current entity id based on the current hostname/path.
+	 * @param $set  The set of metadata we are looking up the entity id in.
+	 */
+	public function getMetaData($entityId, $set = 'saml20-sp-hosted') {
+
+		assert('is_string($set)');
+
+		if($entityId === NULL) {
+			$entityId = $this->getMetaDataCurrentEntityID($set);
 		}
-		if (!isset($currenthost)) {
-			throw new Exception('Could not get HTTP_HOST, in order to resolve default entity ID');
+
+		assert('is_string($entityId)');
+
+		foreach($this->sources as $source) {
+			$metadata = $source->getMetaData($entityId, $set);
+			if($metadata !== NULL) {
+				return $metadata;
+			}
 		}
-		
-		
-		if (isset($this->hostmap[$set][$currenthostwithpath])) return $this->hostmap[$set][$currenthostwithpath];
-		if (isset($this->hostmap[$set][$currenthost])) return $this->hostmap[$set][$currenthost];
-		
-		throw new Exception('Could not find any default metadata entities in set [' . $set . '] for host [' . $currenthost . ' : ' . $currenthostwithpath . ']');
+
+		throw new Exception('Unable to locate metadata for \'' . $entityId . '\' in set \'' . $set . '\'.');
 	}
 
-	abstract public function load($set);
-	abstract public function getMetaData($entityid = null, $set = 'saml20-sp-hosted');
-	
-	
 }
 
 ?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php
index 828ecc7483e14517e3a0096f5e82c40530bbe3bc..e6e670a5034a6f7d9874917ab88dd369c188b925 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php
@@ -1,11 +1,10 @@
 <?php
 
 require_once('SimpleSAML/Configuration.php');
-require_once('SimpleSAML/Utilities.php');
-require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php');
+require_once('SimpleSAML/Metadata/MetaDataStorageSource.php');
 
 /**
- * This file defines a flat file metadata handler.
+ * This file defines a flat file metadata source.
  * Instantiation of session handler objects should be done through
  * the class method getMetadataHandler().
  *
@@ -13,77 +12,119 @@ require_once('SimpleSAML/Metadata/MetaDataStorageHandler.php');
  * @package simpleSAMLphp
  * @version $Id$
  */
-class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Metadata_MetaDataStorageHandler {
+class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Metadata_MetaDataStorageSource {
 
+	/**
+	 * This is the valid metadata sets we know about.
+	 */
+	private static $validSets = array(
+		'saml20-sp-hosted', 'saml20-sp-remote','saml20-idp-hosted', 'saml20-idp-remote',
+		'shib13-sp-hosted', 'shib13-sp-remote', 'shib13-idp-hosted', 'shib13-idp-remote',
+		'openid-provider'
+		);
 
 
+	/**
+	 * This is the directory we will load metadata files from. The path will always end
+	 * with a '/'.
+	 */
+	private $directory;
 
 
-	/* This constructor is included in case it is needed in the the
-	 * future. Including it now allows us to write parent::__construct() in
-	 * the subclasses of this class.
+	/**
+	 * This is an associative array which stores the different metadata sets we have loaded.
 	 */
-	protected function __construct() {
-	}
+	private $cachedMetadata = array();
 
 
+	/**
+	 * This constructor initializes the flatfile metadata storage handler with the
+	 * specified configuration. The configuration is an associative array with the following
+	 * possible elements:
+	 * - 'directory': The directory we should load metadata from. The default directory is
+	 *                set in the 'metadatadir' configuration option in 'config.php'.
+	 *
+	 * @param $config  An associtive array with the configuration for this handler.
+	 */
+	protected function __construct($config) {
+		assert('is_array($config)');
 
-	public function load($set) {
-		$metadata = null;
-		if (!in_array($set, array(
-			'saml20-sp-hosted', 'saml20-sp-remote','saml20-idp-hosted', 'saml20-idp-remote',
-			'shib13-sp-hosted', 'shib13-sp-remote', 'shib13-idp-hosted', 'shib13-idp-remote',
-			'openid-provider'))) {
-				throw new Exception('Trying to load illegal set of Meta data [' . $set . ']');
-		}
-		
 		/* Get the configuration. */
-		$config = SimpleSAML_Configuration::getInstance();
-		assert($config instanceof SimpleSAML_Configuration);
-		
-		$metadatasetfile = $config->getPathValue('metadatadir') . $set . '.php';
-		
+		$globalConfig = SimpleSAML_Configuration::getInstance();
+
+
+		/* Find the path to the directory we should search for metadata in. */
+		if(array_key_exists('directory', $config)) {
+			$this->directory = $config['directory'];
+		} else {
+			$this->directory = $globalConfig->getValue('metadatadir', 'metadata/');
+		}
+
+		/* Resolve this directory relative to the simpleSAMLphp directory (unless it is
+		 * an absolute path).
+		 */
+		$this->directory = $globalConfig->resolvePath($this->directory) . '/';
+	}
+
+
+	/**
+	 * This function loads the given set of metadata from a file our metadata directory.
+	 * This function returns NULL if it is unable to locate the given set in the metadata directory.
+	 *
+	 * @param $set  The set of metadata we are loading.
+	 * @return Associative array with the metadata, or NULL if we are unable to load metadata from the given file.
+	 */
+	private function load($set) {
+
+		$metadatasetfile = $this->directory . $set . '.php';
+
 		if (!file_exists($metadatasetfile)) {
-			throw new Exception('Could not open file: ' . $metadatasetfile);
+			return NULL;
 		}
+
+		$metadata = array();
+
 		include($metadatasetfile);
-		
+
 		if (!is_array($metadata)) {
 			throw new Exception('Could not load metadata set [' . $set . '] from file: ' . $metadatasetfile);
 		}
-		foreach ($metadata AS $key => $entry) { 
-			$this->metadata[$set][$key] = $entry;
-			$this->metadata[$set][$key]['entityid'] = $key;
-			
-			if (isset($entry['host'])) {
-				$this->hostmap[$set][$entry['host']] = $key;
-			}
-			
-		}
 
+		return $metadata;
 	}
 
-	
-	public function getMetaData($entityid = null, $set = 'saml20-sp-hosted') {
-		if (!isset($entityid)) {
-			return $this->getMetaDataCurrent($set);
+
+	/**
+	 * This function retrieves the given set of metadata. It will return an empty array if it is
+	 * unable to locate it.
+	 *
+	 * @param $set  The set of metadata we are retrieving.
+	 * @return Asssociative array with the metadata. Each element in the array is an entity, and the
+	 *         key is the entity id.
+	 */
+	public function getMetadataSet($set) {
+		assert('in_array($set, self::$validSets)');
+
+		if(array_key_exists($set, $this->cachedMetadata)) {
+			return $this->cachedMetadata[$set];
 		}
-		
-		//echo 'find metadata for entityid [' . $entityid . '] in metadata set [' . $set . ']';
-		
-		if (!isset($this->metadata[$set])) {
-			$this->load($set);
+
+		$metadataSet = $this->load($set);
+		if($metadataSet === NULL) {
+			$metadataSet = array();
 		}
-		if (!isset($this->metadata[$set][$entityid]) ) {
-			throw new Exception('Could not find metadata for entityid [' . $entityid . '] in metadata set [' . $set . ']');
+
+		/* Add the entity id of an entry to each entry in the metadata. */
+		foreach ($metadataSet AS $entityId => &$entry) {
+			$entry['entityid'] = $entityId;
 		}
-		return $this->metadata[$set][$entityid];
+
+		$this->cachedMetadata[$set] = $metadataSet;
+
+		return $metadataSet;
 	}
-	
 
 
-	
-	
 }
 
 ?>
\ No newline at end of file
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
new file mode 100644
index 0000000000000000000000000000000000000000..3eaa5c587759bc701ea83b3caf9eafc85cbb1b96
--- /dev/null
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
@@ -0,0 +1,120 @@
+<?php
+
+require_once('SimpleSAML/Metadata/MetaDataStorageHandlerFlatfile.php');
+
+/**
+ * This abstract class defines an interface for metadata storage sources.
+ *
+ * It also contains the overview of the different metadata storage sources.
+ * A metadata storage source can be loaded by passing the configuration of it
+ * to the getSource static function.
+ *
+ * @author Olav Morken, UNINETT AS.
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+abstract class SimpleSAML_Metadata_MetaDataStorageSource {
+
+
+	/**
+	 * This function creates a metadata source based on the given configuration.
+	 * The type of source is based on the 'type' parameter in the configuration.
+	 * The default type is 'flatfile'.
+	 *
+	 * @param $sourceConfig  Associative array with the configuration for this metadata source.
+	 * @return An instance of a metadata source with the given configuration.
+	 */
+	public static function getSource($sourceConfig) {
+
+		assert(is_array($sourceConfig));
+
+		if(array_key_exists('type', $sourceConfig)) {
+			$type = $sourceConfig['type'];
+		} else {
+			$type = 'flatfile';
+		}
+
+		switch($type) {
+		case 'flatfile':
+			return new SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile($sourceConfig);
+		default:
+			throw new Exception('Invalid metadata source type: "' . $type . '".');
+		}
+	}
+
+
+	/**
+	 * This function attempts to generate an associative array with metadata for all entities in the
+	 * given set. The key of the array is the entity id.
+	 *
+	 * A subclass should override this function if it is able to easily generate this list.
+	 *
+	 * @param $set  The set we want to list metadata for.
+	 * @return An associative array with all entities in the given set, or an empty array if we are
+	 *         unable to generate this list.
+	 */
+	public function getMetadataSet($set) {
+		return array();
+	}
+
+
+	/**
+	 * This function resolves an host/path combination to an entity id.
+	 *
+	 * This class implements this function using the getMetadataSet-function. A subclass should
+	 * override this function if it doesn't implement the getMetadataSet function, or if the
+	 * implementation of getMetadataSet is slow.
+	 *
+	 * @param $hostPath  The host/path combination we are looking up.
+	 * @param $set  Which set of metadata we are looking it up in.
+	 * @return An entity id which matches the given host/path combination, or NULL if
+	 *         we are unable to locate one which matches.
+	 */
+	public function getEntityIdFromHostPath($hostPath, $set) {
+
+		$metadataSet = $this->getMetadataSet($set);
+
+		foreach($metadataSet AS $entityId => $entry) {
+
+			if(!array_key_exists('host', $entry)) {
+				continue;
+			}
+
+			if($hostPath === $entry['host']) {
+				return $entityId;
+			}
+		}
+
+		/* No entries matched - we should return NULL. */
+		return NULL;
+	}
+
+
+	/**
+	 * This function retrieves metadata for the given entity id in the given set of metadata.
+	 * It will return NULL if it is unable to locate the metadata.
+	 *
+	 * This class implements this function using the getMetadataSet-function. A subclass should
+	 * override this function if it doesn't implement the getMetadataSet function, or if the
+	 * implementation of getMetadataSet is slow.
+	 *
+	 * @param $entityId  The entity id we are looking up.
+	 * @param $set  The set we are looking for metadata in.
+	 * @return An associative array with metadata for the given entity, or NULL if we are unable to
+	 *         locate the entity.
+	 */
+	public function getMetaData($entityId, $set) {
+
+		assert('is_string($entityId)');
+
+		$metadataSet = $this->getMetadataSet($set);
+
+		if(!array_key_exists($entityId, $metadataSet)) {
+			return NULL;
+		}
+
+		return $metadataSet[$entityId];
+	}
+
+}
+?>
\ No newline at end of file