You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2016/11/04 16:02:33 UTC

[2/3] camel git commit: CAMEL-10419: camel-properties : allow to individually set whether to silently ignore a missing location

CAMEL-10419: camel-properties : allow to individually set whether to silently ignore a missing location


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/a7d41329
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/a7d41329
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/a7d41329

Branch: refs/heads/master
Commit: a7d4132977b76458b6deed3860f76d7bc75c78d2
Parents: 610c5db
Author: lburgazzoli <lb...@gmail.com>
Authored: Thu Nov 3 10:15:14 2016 +0100
Committer: lburgazzoli <lb...@gmail.com>
Committed: Fri Nov 4 16:44:44 2016 +0100

----------------------------------------------------------------------
 .../src/main/docs/properties-component.adoc     |   2 +-
 .../properties/DefaultPropertiesResolver.java   |  50 ++++----
 .../properties/PropertiesComponent.java         | 114 +++++++++++-------
 .../properties/PropertiesLocation.java          | 117 +++++++++++++++++++
 .../properties/PropertiesResolver.java          |   6 +-
 .../PropertiesComponentRestartTest.java         |   6 +-
 .../properties/PropertiesResolverTest.java      |   3 +-
 .../PropertiesAvailableEverywhereTest.java      |   4 +-
 .../PropertiesComponentConfiguration.java       |   8 +-
 .../blueprint/BlueprintPropertiesResolver.java  |  15 +--
 .../xml/AbstractCamelContextFactoryBean.java    |   7 +-
 ...elPropertyPlaceholderLocationDefinition.java |  50 ++++++--
 .../camel/spring/CamelContextFactoryBean.java   |  17 +--
 .../BridgePropertyPlaceholderConfigurer.java    |  12 +-
 ...pringPropertyPlaceholderConfigurer3Test.java |   7 +-
 ...ntPropertiesLocationElementImplicitTest.java |   7 +-
 ...ntPropertiesLocationElementOptionalTest.java |  52 +++++++++
 .../BlueprintPropertiesLocationElementTest.java |   7 +-
 ...roperties-location-element-implicit-test.xml |   2 +-
 ...roperties-location-element-optional-test.xml |  56 +++++++++
 .../properties-location-element-test.xml        |   2 +-
 ...amelSpringPropertiesLocationElementTest.java |   7 +-
 ...ingPropertiesLocationElementTest-context.xml |   3 +-
 23 files changed, 424 insertions(+), 130 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/main/docs/properties-component.adoc
----------------------------------------------------------------------
diff --git a/camel-core/src/main/docs/properties-component.adoc b/camel-core/src/main/docs/properties-component.adoc
index 8ba8bf4..5973dbd 100644
--- a/camel-core/src/main/docs/properties-component.adoc
+++ b/camel-core/src/main/docs/properties-component.adoc
@@ -28,7 +28,7 @@ The Properties component supports 16 options which are listed below.
 [width="100%",cols="2,1m,7",options="header"]
 |=======================================================================
 | Name | Java Type | Description
-| locations | String[] | A list of locations to load properties. This option will override any default locations and only use the locations from this option.
+| locations | List | A list of locations to load properties. This option will override any default locations and only use the locations from this option.
 | location | String | A list of locations to load properties. You can use comma to separate multiple locations. This option will override any default locations and only use the locations from this option.
 | encoding | String | Encoding to use when loading properties file from the file system or classpath. If no encoding has been set then the properties files is loaded using ISO-8859-1 encoding (latin-1) as documented by link java.util.Propertiesload(java.io.InputStream)
 | propertiesResolver | PropertiesResolver | To use a custom PropertiesResolver

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/main/java/org/apache/camel/component/properties/DefaultPropertiesResolver.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/component/properties/DefaultPropertiesResolver.java b/camel-core/src/main/java/org/apache/camel/component/properties/DefaultPropertiesResolver.java
index e1b46c9..4fef9dc 100644
--- a/camel-core/src/main/java/org/apache/camel/component/properties/DefaultPropertiesResolver.java
+++ b/camel-core/src/main/java/org/apache/camel/component/properties/DefaultPropertiesResolver.java
@@ -23,12 +23,12 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.util.IOHelper;
-import org.apache.camel.util.ObjectHelper;
 
 /**
  * Default {@link org.apache.camel.component.properties.PropertiesResolver} which can resolve properties
@@ -47,35 +47,38 @@ public class DefaultPropertiesResolver implements PropertiesResolver {
         this.propertiesComponent = propertiesComponent;
     }
 
-    public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception {
+    public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception {
         Properties answer = new Properties();
+        Properties prop;
 
-        for (String path : uri) {
-            if (path.startsWith("ref:")) {
-                Properties prop = loadPropertiesFromRegistry(context, ignoreMissingLocation, path);
+        for (PropertiesLocation location : locations) {
+            switch(location.getResolver()) {
+            case "ref":
+                prop = loadPropertiesFromRegistry(context, ignoreMissingLocation, location);
                 prop = prepareLoadedProperties(prop);
                 answer.putAll(prop);
-            } else if (path.startsWith("file:")) {
-                Properties prop = loadPropertiesFromFilePath(context, ignoreMissingLocation, path);
+                break;
+            case "file":
+                prop = loadPropertiesFromFilePath(context, ignoreMissingLocation, location);
                 prop = prepareLoadedProperties(prop);
                 answer.putAll(prop);
-            } else {
+                break;
+            case "classpath":
+            default:
                 // default to classpath
-                Properties prop = loadPropertiesFromClasspath(context, ignoreMissingLocation, path);
+                prop = loadPropertiesFromClasspath(context, ignoreMissingLocation, location);
                 prop = prepareLoadedProperties(prop);
                 answer.putAll(prop);
+                break;
             }
         }
 
         return answer;
     }
 
-    protected Properties loadPropertiesFromFilePath(CamelContext context, boolean ignoreMissingLocation, String path) throws IOException {
+    protected Properties loadPropertiesFromFilePath(CamelContext context, boolean ignoreMissingLocation, PropertiesLocation location) throws IOException {
         Properties answer = new Properties();
-
-        if (path.startsWith("file:")) {
-            path = ObjectHelper.after(path, "file:");
-        }
+        String path = location.getPath();
 
         InputStream is = null;
         Reader reader = null;
@@ -88,7 +91,7 @@ public class DefaultPropertiesResolver implements PropertiesResolver {
                 answer.load(is);
             }
         } catch (FileNotFoundException e) {
-            if (!ignoreMissingLocation) {
+            if (!ignoreMissingLocation && !location.isOptional()) {
                 throw e;
             }
         } finally {
@@ -98,17 +101,14 @@ public class DefaultPropertiesResolver implements PropertiesResolver {
         return answer;
     }
 
-    protected Properties loadPropertiesFromClasspath(CamelContext context, boolean ignoreMissingLocation, String path) throws IOException {
+    protected Properties loadPropertiesFromClasspath(CamelContext context, boolean ignoreMissingLocation, PropertiesLocation location) throws IOException {
         Properties answer = new Properties();
-
-        if (path.startsWith("classpath:")) {
-            path = ObjectHelper.after(path, "classpath:");
-        }
+        String path = location.getPath();
 
         InputStream is = context.getClassResolver().loadResourceAsStream(path);
         Reader reader = null;
         if (is == null) {
-            if (!ignoreMissingLocation) {
+            if (!ignoreMissingLocation && !location.isOptional()) {
                 throw new FileNotFoundException("Properties file " + path + " not found in classpath");
             }
         } else {
@@ -127,10 +127,8 @@ public class DefaultPropertiesResolver implements PropertiesResolver {
     }
 
     @SuppressWarnings({"rawtypes", "unchecked"})
-    protected Properties loadPropertiesFromRegistry(CamelContext context, boolean ignoreMissingLocation, String path) throws IOException {
-        if (path.startsWith("ref:")) {
-            path = ObjectHelper.after(path, "ref:");
-        }
+    protected Properties loadPropertiesFromRegistry(CamelContext context, boolean ignoreMissingLocation, PropertiesLocation location) throws IOException {
+        String path = location.getPath();
         Properties answer;
         try {
             answer = context.getRegistry().lookupByNameAndType(path, Properties.class);
@@ -140,7 +138,7 @@ public class DefaultPropertiesResolver implements PropertiesResolver {
             answer = new Properties();
             answer.putAll(map);
         }
-        if (answer == null && (!ignoreMissingLocation)) {
+        if (answer == null && (!ignoreMissingLocation && !location.isOptional())) {
             throw new FileNotFoundException("Properties " + path + " not found in registry");
         }
         return answer != null ? answer : new Properties();

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java b/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
index 3ad3067..27fc7ed 100644
--- a/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
+++ b/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
@@ -20,10 +20,12 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.stream.Collectors;
 
 import org.apache.camel.Endpoint;
 import org.apache.camel.impl.UriEndpointComponent;
@@ -92,7 +94,7 @@ public class PropertiesComponent extends UriEndpointComponent {
     private PropertiesResolver propertiesResolver = new DefaultPropertiesResolver(this);
     private PropertiesParser propertiesParser = new DefaultPropertiesParser(this);
     private boolean isDefaultCreated;
-    private String[] locations;
+    private List<PropertiesLocation> locations = Collections.emptyList();
     private boolean ignoreMissingLocation;
     private String encoding;
     private boolean cache = true;
@@ -135,17 +137,18 @@ public class PropertiesComponent extends UriEndpointComponent {
 
     @Override
     protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
-        String[] paths = locations;
+        List<PropertiesLocation> paths = locations;
+
+        Boolean ignoreMissingLocationLoc = getAndRemoveParameter(parameters, "ignoreMissingLocation", Boolean.class);
+        if (ignoreMissingLocationLoc != null) {
+            ignoreMissingLocation = ignoreMissingLocationLoc;
+        }
 
         // override default locations
         String locations = getAndRemoveParameter(parameters, "locations", String.class);
-        Boolean ignoreMissingLocationLoc = getAndRemoveParameter(parameters, "ignoreMissingLocation", Boolean.class);
         if (locations != null) {
             LOG.trace("Overriding default locations with location: {}", locations);
-            paths = locations.split(",");
-        }
-        if (ignoreMissingLocationLoc != null) {
-            ignoreMissingLocation = ignoreMissingLocationLoc;
+            paths = Arrays.stream(locations.split(",")).map(PropertiesLocation::new).collect(Collectors.toList());
         }
 
         String endpointUri = parseUri(remaining, paths);
@@ -162,7 +165,15 @@ public class PropertiesComponent extends UriEndpointComponent {
         return parseUri(uri, locations);
     }
 
-    public String parseUri(String uri, String... paths) throws Exception {
+    public String parseUri(String uri, String... uris) throws Exception {
+        return parseUri(
+            uri,
+            uris != null
+                ? Arrays.stream(uris).map(PropertiesLocation::new).collect(Collectors.toList())
+                : Collections.emptyList());
+    }
+
+    public String parseUri(String uri, List<PropertiesLocation> paths) throws Exception {
         Properties prop = new Properties();
 
         // use initial properties
@@ -174,7 +185,7 @@ public class PropertiesComponent extends UriEndpointComponent {
         if (paths != null) {
             // location may contain JVM system property or OS environment variables
             // so we need to parse those
-            String[] locations = parseLocations(paths);
+            List<PropertiesLocation> locations = parseLocations(paths);
 
             // check cache first
             CacheKey key = new CacheKey(locations);
@@ -209,10 +220,14 @@ public class PropertiesComponent extends UriEndpointComponent {
         
         if (propertiesParser instanceof AugmentedPropertyNameAwarePropertiesParser) {
             return ((AugmentedPropertyNameAwarePropertiesParser) propertiesParser).parseUri(
-                uri, prop,
-                prefixToken, suffixToken,
-                propertyPrefixResolved, propertySuffixResolved,
-                fallbackToUnaugmentedProperty, defaultFallbackEnabled);
+                uri,
+                prop,
+                prefixToken,
+                suffixToken,
+                propertyPrefixResolved,
+                propertySuffixResolved,
+                fallbackToUnaugmentedProperty,
+                defaultFallbackEnabled);
         } else {
             return propertiesParser.parseUri(uri, prop, prefixToken, suffixToken);
         }
@@ -225,7 +240,7 @@ public class PropertiesComponent extends UriEndpointComponent {
         return isDefaultCreated;
     }
 
-    public String[] getLocations() {
+    public List<PropertiesLocation> getLocations() {
         return locations;
     }
 
@@ -233,27 +248,38 @@ public class PropertiesComponent extends UriEndpointComponent {
      * A list of locations to load properties.
      * This option will override any default locations and only use the locations from this option.
      */
-    public void setLocations(String[] locations) {
-        // make sure to trim as people may use new lines when configuring using XML
-        // and do this in the setter as Spring/Blueprint resolves placeholders before Camel is being started
-        if (locations != null && locations.length > 0) {
-            for (int i = 0; i < locations.length; i++) {
-                String loc = locations[i];
-                locations[i] = loc.trim();
+    public void setLocations(List<PropertiesLocation> locations) {
+        this.locations = Collections.unmodifiableList(locations);
+    }
+
+    /**
+     * A list of locations to load properties.
+     * This option will override any default locations and only use the locations from this option.
+     */
+    public void setLocations(String[] locationStrings) {
+        List<PropertiesLocation> locations = new ArrayList<>();
+        if (locationStrings != null) {
+            for (String locationString : locationStrings) {
+                locations.add(new PropertiesLocation(locationString));
             }
         }
 
-        this.locations = locations;
+        setLocations(locations);
     }
 
     /**
      * A list of locations to load properties.
      * This option will override any default locations and only use the locations from this option.
      */
-    public void setLocations(Collection<String> locations) {
-        if (locations != null && !locations.isEmpty()) {
-            setLocations(locations.toArray(new String[locations.size()]));
+    public void setLocations(Collection<String> locationStrings) {
+        List<PropertiesLocation> locations = new ArrayList<>();
+        if (locationStrings != null) {
+            for (String locationString : locationStrings) {
+                locations.add(new PropertiesLocation(locationString));
+            }
         }
+
+        setLocations(locations);
     }
 
     /**
@@ -494,20 +520,24 @@ public class PropertiesComponent extends UriEndpointComponent {
         super.doStop();
     }
 
-    private String[] parseLocations(String[] locations) {
-        List<String> answer = new ArrayList<String>();
+    private List<PropertiesLocation> parseLocations(List<PropertiesLocation> locations) {
+        List<PropertiesLocation> answer = new ArrayList<>();
 
-        for (String location : locations) {
+        for (PropertiesLocation location : locations) {
             LOG.trace("Parsing location: {} ", location);
 
             try {
-                location = FilePathResolver.resolvePath(location);
-                LOG.debug("Parsed location: {} ", location);
-                if (ObjectHelper.isNotEmpty(location)) {
-                    answer.add(location);
+                String path = FilePathResolver.resolvePath(location.getPath());
+                LOG.debug("Parsed location: {} ", path);
+                if (ObjectHelper.isNotEmpty(path)) {
+                    answer.add(new PropertiesLocation(
+                        location.getResolver(),
+                        path,
+                        location.isOptional())
+                    );
                 }
             } catch (IllegalArgumentException e) {
-                if (!ignoreMissingLocation) {
+                if (!ignoreMissingLocation && !location.isOptional()) {
                     throw e;
                 } else {
                     LOG.debug("Ignored missing location: {}", location);
@@ -516,7 +546,7 @@ public class PropertiesComponent extends UriEndpointComponent {
         }
 
         // must return a not-null answer
-        return answer.toArray(new String[answer.size()]);
+        return answer;
     }
 
     /**
@@ -524,10 +554,10 @@ public class PropertiesComponent extends UriEndpointComponent {
      */
     private static final class CacheKey implements Serializable {
         private static final long serialVersionUID = 1L;
-        private final String[] locations;
+        private final List<PropertiesLocation> locations;
 
-        private CacheKey(String[] locations) {
-            this.locations = locations;
+        private CacheKey(List<PropertiesLocation> locations) {
+            this.locations = new ArrayList<>(locations);
         }
 
         @Override
@@ -541,21 +571,17 @@ public class PropertiesComponent extends UriEndpointComponent {
 
             CacheKey that = (CacheKey) o;
 
-            if (!Arrays.equals(locations, that.locations)) {
-                return false;
-            }
-
-            return true;
+            return locations.equals(that.locations);
         }
 
         @Override
         public int hashCode() {
-            return locations != null ? Arrays.hashCode(locations) : 0;
+            return locations != null ? locations.hashCode() : 0;
         }
 
         @Override
         public String toString() {
-            return "LocationKey[" + Arrays.asList(locations).toString() + "]";
+            return "LocationKey[" + locations.toString() + "]";
         }
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesLocation.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesLocation.java b/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesLocation.java
new file mode 100644
index 0000000..46395e6
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesLocation.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.properties;
+
+import org.apache.camel.util.ObjectHelper;
+
+public class PropertiesLocation {
+    private final String resolver;
+    private final String path;
+    private final boolean optional;
+
+    public PropertiesLocation(String location) {
+        // make sure to trim as people may use new lines when configuring using XML
+        // and do this in the setter as Spring/Blueprint resolves placeholders before
+        // Camel is being started
+        location = location.trim();
+
+        int idx = location.indexOf(':');
+        if (idx != -1) {
+            this.resolver = location.substring(0, idx);
+            location = location.substring(idx + 1);
+        } else {
+            this.resolver = "classpath";
+        }
+
+        idx = location.lastIndexOf(';');
+        if (idx != -1) {
+            this.optional = ObjectHelper.after(location.substring(idx + 1), "optional=", Boolean::valueOf).orElse(false);
+            location = location.substring(0, idx);
+        } else {
+            this.optional = false;
+        }
+
+        this.path = location;
+    }
+
+    public PropertiesLocation(String resolver, String path) {
+        this(resolver, path, false);
+    }
+
+    public PropertiesLocation(String resolver, String path, Boolean optional) {
+        this.resolver = resolver;
+        this.path = path;
+        this.optional = optional;
+    }
+
+    // *****************************
+    // Getters
+    // *****************************
+
+    public String getResolver() {
+        return resolver;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public boolean isOptional() {
+        return optional;
+    }
+
+    // *****************************
+    // Equals/HashCode/ToString
+    // *****************************
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        PropertiesLocation location = (PropertiesLocation) o;
+
+        if (optional != location.optional) {
+            return false;
+        }
+        if (resolver != null ? !resolver.equals(location.resolver) : location.resolver != null) {
+            return false;
+        }
+        return path != null ? path.equals(location.path) : location.path == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = resolver != null ? resolver.hashCode() : 0;
+        result = 31 * result + (path != null ? path.hashCode() : 0);
+        result = 31 * result + (optional ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "PropertiesLocation{"
+            + "resolver='" + resolver + '\''
+            + ", path='" + path + '\''
+            + ", optional=" + optional
+            + '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesResolver.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesResolver.java b/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesResolver.java
index e5a2dbb..f6923a5 100644
--- a/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesResolver.java
+++ b/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesResolver.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.properties;
 
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
@@ -34,10 +35,9 @@ public interface PropertiesResolver {
      *
      * @param context the camel context
      * @param ignoreMissingLocation ignore silently if the property file is missing
-     * @param uri uri(s) defining the source(s)
+     * @param locations location(s) defining the source(s)
      * @return the properties
      * @throws Exception is thrown if resolving the properties failed
      */
-    Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception;
-    
+    Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception;
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentRestartTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentRestartTest.java b/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentRestartTest.java
index 6d7c919..c630df6 100644
--- a/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentRestartTest.java
+++ b/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentRestartTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.properties;
 
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
@@ -50,12 +51,11 @@ public class PropertiesComponentRestartTest extends ContextTestSupport {
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
-
         final PropertiesComponent pc = new PropertiesComponent("classpath:org/apache/camel/component/properties/myproperties.properties");
         pc.setPropertiesResolver(new PropertiesResolver() {
-            public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception {
+            public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception {
                 resolvedCount++;
-                return new DefaultPropertiesResolver(pc).resolveProperties(context, ignoreMissingLocation, uri);
+                return new DefaultPropertiesResolver(pc).resolveProperties(context, ignoreMissingLocation, locations);
             }
         });
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesResolverTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesResolverTest.java b/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesResolverTest.java
index 8d2b89a..0beca70 100644
--- a/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesResolverTest.java
+++ b/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesResolverTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.properties;
 
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
@@ -63,7 +64,7 @@ public class PropertiesResolverTest extends ContextTestSupport {
 
     public static class MyCustomResolver implements PropertiesResolver {
 
-        public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception {
+        public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception {
             Properties answer = new Properties();
             answer.put("foo", "mock:result");
             return answer;

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/camel-core/src/test/java/org/apache/camel/issues/PropertiesAvailableEverywhereTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/issues/PropertiesAvailableEverywhereTest.java b/camel-core/src/test/java/org/apache/camel/issues/PropertiesAvailableEverywhereTest.java
index 94a9086..b020128 100644
--- a/camel-core/src/test/java/org/apache/camel/issues/PropertiesAvailableEverywhereTest.java
+++ b/camel-core/src/test/java/org/apache/camel/issues/PropertiesAvailableEverywhereTest.java
@@ -16,12 +16,14 @@
  */
 package org.apache.camel.issues;
 
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.component.properties.PropertiesResolver;
 
 public class PropertiesAvailableEverywhereTest extends ContextTestSupport {
@@ -36,7 +38,7 @@ public class PropertiesAvailableEverywhereTest extends ContextTestSupport {
         pc.setLocations(new String[0]);
         pc.setPropertiesResolver(new PropertiesResolver() {
             @Override
-            public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) {
+            public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) {
                 return properties;
             }
         });

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/properties/springboot/PropertiesComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/properties/springboot/PropertiesComponentConfiguration.java b/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/properties/springboot/PropertiesComponentConfiguration.java
index 8eab06c..0ed1d4e 100644
--- a/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/properties/springboot/PropertiesComponentConfiguration.java
+++ b/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/properties/springboot/PropertiesComponentConfiguration.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.properties.springboot;
 
+import java.util.List;
 import java.util.Properties;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.component.properties.PropertiesParser;
 import org.apache.camel.component.properties.PropertiesResolver;
 import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -35,7 +37,7 @@ public class PropertiesComponentConfiguration {
      * A list of locations to load properties. This option will override any
      * default locations and only use the locations from this option.
      */
-    private String[] locations;
+    private List<PropertiesLocation> locations;
     /**
      * A list of locations to load properties. You can use comma to separate
      * multiple locations. This option will override any default locations and
@@ -114,11 +116,11 @@ public class PropertiesComponentConfiguration {
      */
     private Integer systemPropertiesMode;
 
-    public String[] getLocations() {
+    public List<PropertiesLocation> getLocations() {
         return locations;
     }
 
-    public void setLocations(String[] locations) {
+    public void setLocations(List<PropertiesLocation> locations) {
         this.locations = locations;
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintPropertiesResolver.java
----------------------------------------------------------------------
diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintPropertiesResolver.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintPropertiesResolver.java
index aa36d1f..6c985c0 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintPropertiesResolver.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/BlueprintPropertiesResolver.java
@@ -16,11 +16,13 @@
  */
 package org.apache.camel.blueprint;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.component.properties.PropertiesResolver;
-import org.apache.camel.util.ObjectHelper;
 
 /**
  * A {@link PropertiesResolver} which supports the <tt>blueprint</tt> scheme.
@@ -40,20 +42,19 @@ public class BlueprintPropertiesResolver implements PropertiesResolver {
     }
 
     @Override
-    public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... urls) throws Exception {
+    public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception {
         Properties answer = new Properties();
 
         boolean explicit = false;
 
-        for (String url : urls) {
-            if (url.startsWith("blueprint:")) {
-                String ref = ObjectHelper.after(url, "blueprint:");
-                blueprint.addPropertyPlaceholder(ref);
+        for (PropertiesLocation location : locations) {
+            if ("blueprint".equals(location.getResolver())) {
+                blueprint.addPropertyPlaceholder(location.getPath());
                 // indicate an explicit blueprint id was configured
                 explicit = true;
             } else {
                 // delegate the url
-                answer.putAll(delegate.resolveProperties(context, ignoreMissingLocation, url));
+                answer.putAll(delegate.resolveProperties(context, ignoreMissingLocation, Collections.singletonList(location)));
             }
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index a2b5e3f..fe5b826 100644
--- a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -41,6 +41,7 @@ import org.apache.camel.builder.ErrorHandlerBuilderRef;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.properties.PropertiesComponent;
 import org.apache.camel.component.properties.PropertiesFunction;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.component.properties.PropertiesParser;
 import org.apache.camel.component.properties.PropertiesResolver;
 import org.apache.camel.management.DefaultManagementAgent;
@@ -567,16 +568,16 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
         if (getCamelPropertyPlaceholder() != null) {
             CamelPropertyPlaceholderDefinition def = getCamelPropertyPlaceholder();
 
-            List<String> locations = new ArrayList<>();
+            List<PropertiesLocation> locations = new ArrayList<>();
 
             if (def.getLocation() != null) {
                 ObjectHelper.createIterable(def.getLocation()).forEach(
-                    location -> locations.add((String) location)
+                    location -> locations.add(new PropertiesLocation((String) location))
                 );
             }
             if (def.getLocations() != null) {
                 def.getLocations().forEach(
-                    definition -> locations.add(definition.getPath())
+                    definition -> locations.add(definition.toLocation())
                 );
             }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/CamelPropertyPlaceholderLocationDefinition.java
----------------------------------------------------------------------
diff --git a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/CamelPropertyPlaceholderLocationDefinition.java b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/CamelPropertyPlaceholderLocationDefinition.java
index 4923684..b2e7005 100644
--- a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/CamelPropertyPlaceholderLocationDefinition.java
+++ b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/CamelPropertyPlaceholderLocationDefinition.java
@@ -19,6 +19,7 @@ package org.apache.camel.core.xml;
 import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.model.IdentifiedType;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.util.ObjectHelper;
@@ -29,10 +30,24 @@ import org.apache.camel.util.ObjectHelper;
 @Metadata(label = "spring,configuration")
 @XmlRootElement(name = "propertiesLocation")
 public class CamelPropertyPlaceholderLocationDefinition extends IdentifiedType {
+    @XmlAttribute @Metadata(defaultValue = "classpath")
+    public String resolver;
     @XmlAttribute(required = true)
     public String path;
-    @XmlAttribute
-    public String resolver;
+    @XmlAttribute @Metadata(defaultValue = "false")
+    public Boolean optional;
+
+
+    public String getResolver() {
+        return resolver;
+    }
+
+    /**
+     * The resolver to use to locate the location
+     */
+    public void setResolver(String resolver) {
+        this.resolver = resolver;
+    }
 
     public String getPath() {
         return path;
@@ -45,18 +60,35 @@ public class CamelPropertyPlaceholderLocationDefinition extends IdentifiedType {
         this.path = path;
     }
 
-    public String getResolver() {
-        return resolver;
+    public Boolean getOptional() {
+        return optional;
     }
 
     /**
-     * The resolver to use to locate the location
+     * If the location is optional.
      */
-    public void setResolver(String resolver) {
-        this.resolver = resolver;
+    public void setOptional(Boolean optional) {
+        this.optional = optional;
+    }
+
+    @Override
+    public String toString() {
+        String answer = path;
+        if (ObjectHelper.isNotEmpty(resolver)) {
+            answer = resolver + ":" + answer;
+        }
+        if (ObjectHelper.isNotEmpty(optional)) {
+            answer = answer + ";optional=true";
+        }
+
+        return answer;
     }
 
-    public String getLocation() {
-        return ObjectHelper.isEmpty(resolver) ? path : resolver + path;
+    public PropertiesLocation toLocation() {
+        return new PropertiesLocation(
+            resolver != null ? resolver : "classpath",
+            path,
+            optional != null ? optional : false
+        );
     }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
index ed930f3..651f280 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java
@@ -35,6 +35,7 @@ import org.apache.camel.ShutdownRunningTask;
 import org.apache.camel.TypeConverterExists;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.core.xml.AbstractCamelContextFactoryBean;
 import org.apache.camel.core.xml.CamelJMXAgentDefinition;
 import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition;
@@ -312,21 +313,15 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
             // replace existing resolver with us
             configurer.setResolver(pc.getPropertiesResolver());
             configurer.setParser(pc.getPropertiesParser());
-            String ref = "ref:" + id;
             // use the bridge to handle the resolve and parsing
             pc.setPropertiesResolver(configurer);
             pc.setPropertiesParser(configurer);
+
             // and update locations to have our as ref first
-            String[] locations = pc.getLocations();
-            String[] updatedLocations;
-            if (locations != null && locations.length > 0) {
-                updatedLocations = new String[locations.length + 1];
-                updatedLocations[0] = ref;
-                System.arraycopy(locations, 0, updatedLocations, 1, locations.length);
-            } else {
-                updatedLocations = new String[]{ref};
-            }
-            pc.setLocations(updatedLocations);
+            List<PropertiesLocation> locations = new ArrayList<>(pc.getLocations());
+            locations.add(0, new PropertiesLocation("ref", id));
+
+            pc.setLocations(locations);
         } else if (beans.size() > 1) {
             LOG.warn("Cannot bridge Camel and Spring property placeholders, as exact only 1 bean of type BridgePropertyPlaceholderConfigurer"
                     + " must be defined, was {} beans defined.", beans.size());

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java b/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java
index 84b1e6f..58939ca 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/spring/spi/BridgePropertyPlaceholderConfigurer.java
@@ -16,10 +16,13 @@
  */
 package org.apache.camel.spring.spi;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.component.properties.AugmentedPropertyNameAwarePropertiesParser;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.apache.camel.component.properties.PropertiesParser;
 import org.apache.camel.component.properties.PropertiesResolver;
 import org.springframework.beans.BeansException;
@@ -129,12 +132,11 @@ public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConf
     }
 
     @Override
-    public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception {
+    public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception {
         // return the spring properties, if it
         Properties answer = new Properties();
-        for (String u : uri) {
-            String ref = "ref:" + id;
-            if (ref.equals(u)) {
+        for (PropertiesLocation location : locations) {
+            if ("ref".equals(location.getResolver()) && id.equals(location.getPath())) {
                 answer.putAll(properties);
             } else if (resolver != null) {
                 boolean flag = ignoreMissingLocation;
@@ -142,7 +144,7 @@ public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConf
                 if (ignoreResourceNotFound != null) {
                     flag = ignoreResourceNotFound;
                 }
-                Properties p = resolver.resolveProperties(context, flag, u);
+                Properties p = resolver.resolveProperties(context, flag, Collections.singletonList(location));
                 if (p != null) {
                     answer.putAll(p);
                 }

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-spring/src/test/java/org/apache/camel/component/properties/CamelSpringPropertyPlaceholderConfigurer3Test.java
----------------------------------------------------------------------
diff --git a/components/camel-spring/src/test/java/org/apache/camel/component/properties/CamelSpringPropertyPlaceholderConfigurer3Test.java b/components/camel-spring/src/test/java/org/apache/camel/component/properties/CamelSpringPropertyPlaceholderConfigurer3Test.java
index e6d160a..586853b 100644
--- a/components/camel-spring/src/test/java/org/apache/camel/component/properties/CamelSpringPropertyPlaceholderConfigurer3Test.java
+++ b/components/camel-spring/src/test/java/org/apache/camel/component/properties/CamelSpringPropertyPlaceholderConfigurer3Test.java
@@ -16,12 +16,12 @@
  */
 package org.apache.camel.component.properties;
 
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.spring.SpringTestSupport;
 import org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer;
-
 import org.springframework.context.support.AbstractXmlApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
@@ -68,15 +68,14 @@ public class CamelSpringPropertyPlaceholderConfigurer3Test extends SpringTestSup
     private static class MyBridgePropertyPlaceholderConfigurer extends BridgePropertyPlaceholderConfigurer {
 
         @Override
-        public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception {
-            Properties answer = super.resolveProperties(context, ignoreMissingLocation, uri);
+        public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception {
+            Properties answer = super.resolveProperties(context, ignoreMissingLocation, locations);
 
             // define the additional properties we need to provide so that the uri "direct:{{foo}}" by the "from" clause
             // as well as "{{scheme}}{{separator}}{{context-path}}" by the "to" clause can be properly resolved. please
             // note that in this simple test we just add these properties hard-coded below but of course the mechanism to
             // retrieve these extra properties can be anything else, e.g. through the entries inside a database table etc.
             answer.put("foo", "bar");
-
             answer.put("scheme", "mock");
             answer.put("separator", ":");
             answer.put("context-path", "result");

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementImplicitTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementImplicitTest.java b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementImplicitTest.java
index 89a7451..b2c042d 100644
--- a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementImplicitTest.java
+++ b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementImplicitTest.java
@@ -17,8 +17,11 @@
 
 package org.apache.camel.test.blueprint;
 
+import java.util.List;
+
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.junit.Test;
 
 public class BlueprintPropertiesLocationElementImplicitTest extends CamelBlueprintTestSupport {
@@ -37,10 +40,10 @@ public class BlueprintPropertiesLocationElementImplicitTest extends CamelBluepri
         PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
         assertNotNull("Properties component not defined", pc);
 
-        String[] locations = pc.getLocations();
+        List<PropertiesLocation> locations = pc.getLocations();
 
         assertNotNull(locations);
-        assertEquals("Properties locations", 2, locations.length);
+        assertEquals("Properties locations", 2, locations.size());
 
         template.sendBody("direct:start", null);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementOptionalTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementOptionalTest.java b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementOptionalTest.java
new file mode 100644
index 0000000..e8d4a62
--- /dev/null
+++ b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementOptionalTest.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.test.blueprint;
+
+import java.util.List;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.component.properties.PropertiesLocation;
+import org.junit.Test;
+
+public class BlueprintPropertiesLocationElementOptionalTest extends CamelBlueprintTestSupport {
+    @Override
+    protected String getBlueprintDescriptor() {
+        return "org/apache/camel/test/blueprint/properties-location-element-optional-test.xml";
+    }
+
+    @Test
+    public void testPropertiesLocationElement() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedHeaderReceived("property-1", "property-value-1");
+        mock.expectedHeaderReceived("property-2", "property-value-2");
+        mock.expectedHeaderReceived("cm", "cm-value");
+
+        PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
+        assertNotNull("Properties component not defined", pc);
+
+        List<PropertiesLocation> locations = pc.getLocations();
+
+        assertNotNull(locations);
+        assertEquals("Properties locations", 3, locations.size());
+
+        template.sendBody("direct:start", null);
+
+        mock.assertIsSatisfied();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementTest.java b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementTest.java
index d05ce78..8548953 100644
--- a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementTest.java
+++ b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/BlueprintPropertiesLocationElementTest.java
@@ -16,8 +16,11 @@
  */
 package org.apache.camel.test.blueprint;
 
+import java.util.List;
+
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.junit.Test;
 
 public class BlueprintPropertiesLocationElementTest extends CamelBlueprintTestSupport {
@@ -36,10 +39,10 @@ public class BlueprintPropertiesLocationElementTest extends CamelBlueprintTestSu
         PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
         assertNotNull("Properties component not defined", pc);
 
-        String[] locations = pc.getLocations();
+        List<PropertiesLocation> locations = pc.getLocations();
 
         assertNotNull(locations);
-        assertEquals("Properties locations", 3, locations.length);
+        assertEquals("Properties locations", 3, locations.size());
 
         template.sendBody("direct:start", null);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-implicit-test.xml
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-implicit-test.xml b/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-implicit-test.xml
index ffe6986..4856892 100644
--- a/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-implicit-test.xml
+++ b/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-implicit-test.xml
@@ -32,7 +32,7 @@
 
   <camelContext xmlns="http://camel.apache.org/schema/blueprint">
     <propertyPlaceholder id="property-placeholder-camel">
-      <propertiesLocation path="classpath:org/apache/camel/test/blueprint/properties-location-element-1.properties"/>
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-1.properties"/>
       <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-2.properties"/>
     </propertyPlaceholder>
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-optional-test.xml
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-optional-test.xml b/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-optional-test.xml
new file mode 100644
index 0000000..a53afdb
--- /dev/null
+++ b/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-optional-test.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
+           xsi:schemaLocation="
+             http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0
+             http://aries.apache.org/schemas/blueprint-cm/blueprint-cm-1.1.0.xsd
+             http://www.osgi.org/xmlns/blueprint/v1.0.0
+             http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+
+  <cm:property-placeholder id="properties-element" persistent-id="properties.element">
+    <cm:default-properties>
+      <cm:property name="cm-key" value="cm-value" />
+    </cm:default-properties>
+  </cm:property-placeholder>
+
+  <camelContext xmlns="http://camel.apache.org/schema/blueprint">
+    <propertyPlaceholder id="property-placeholder-camel">
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-1.properties"/>
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-2.properties"/>
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-3.properties" optional="true"/>
+    </propertyPlaceholder>
+
+    <route>
+      <from uri="direct:start"/>
+      <setHeader headerName="property-1">
+        <constant>{{property-key-1}}</constant>
+      </setHeader>
+      <setHeader headerName="property-2">
+        <constant>{{property-key-2}}</constant>
+      </setHeader>
+      <setHeader headerName="cm">
+        <constant>{{cm-key}}</constant>
+      </setHeader>
+      <to uri="mock:result"/>
+    </route>
+
+  </camelContext>
+
+</blueprint>

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-test.xml
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-test.xml b/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-test.xml
index 9c81873..92d403b 100644
--- a/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-test.xml
+++ b/components/camel-test-blueprint/src/test/resources/org/apache/camel/test/blueprint/properties-location-element-test.xml
@@ -32,7 +32,7 @@
 
   <camelContext xmlns="http://camel.apache.org/schema/blueprint">
     <propertyPlaceholder id="property-placeholder-camel" location="blueprint:properties-element">
-      <propertiesLocation path="classpath:org/apache/camel/test/blueprint/properties-location-element-1.properties"/>
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-1.properties"/>
       <propertiesLocation resolver="classpath" path="org/apache/camel/test/blueprint/properties-location-element-2.properties"/>
     </propertyPlaceholder>
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest.java b/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest.java
index 89a5186..2712ba2 100644
--- a/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest.java
+++ b/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest.java
@@ -16,12 +16,15 @@
  */
 package org.apache.camel.test.spring;
 
+import java.util.List;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.EndpointInject;
 import org.apache.camel.Produce;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.component.properties.PropertiesLocation;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -53,10 +56,10 @@ public class CamelSpringPropertiesLocationElementTest {
         PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
         assertNotNull("Properties component not defined", pc);
 
-        String[] locations = pc.getLocations();
+        List<PropertiesLocation> locations = pc.getLocations();
 
         assertNotNull(locations);
-        assertEquals("Properties locations", 3, locations.length);
+        assertEquals("Properties locations", 4, locations.size());
 
         producer.sendBody("direct:start", null);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a7d41329/components/camel-test-spring/src/test/resources/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest-context.xml
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/test/resources/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest-context.xml b/components/camel-test-spring/src/test/resources/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest-context.xml
index 247b551..2331f7b 100644
--- a/components/camel-test-spring/src/test/resources/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest-context.xml
+++ b/components/camel-test-spring/src/test/resources/org/apache/camel/test/spring/CamelSpringPropertiesLocationElementTest-context.xml
@@ -23,8 +23,9 @@
 
   <camelContext xmlns="http://camel.apache.org/schema/spring">
     <propertyPlaceholder id="property-placeholder-camel" location="classpath:org/apache/camel/test/spring/properties-location-element-3.properties">
-      <propertiesLocation path="classpath:org/apache/camel/test/spring/properties-location-element-1.properties"/>
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/spring/properties-location-element-1.properties"/>
       <propertiesLocation resolver="classpath" path="org/apache/camel/test/spring/properties-location-element-2.properties"/>
+      <propertiesLocation resolver="classpath" path="org/apache/camel/test/spring/properties-location-element-4.properties" optional="true"/>
     </propertyPlaceholder>
 
     <route>