GithubHelp home page GithubHelp logo

spring-cloud / spring-cloud-connectors Goto Github PK

View Code? Open in Web Editor NEW
182.0 182.0 160.0 2.63 MB

Library to let cloud applications connect to services

License: Apache License 2.0

Java 98.81% Shell 1.05% Dockerfile 0.14%

spring-cloud-connectors's Introduction

Spring Cloud Connectors

Spring Cloud Connectors provides a simple abstraction that JVM-based applications can use to discover information about the cloud environment on which they are running, connect to services, and have discovered services registered as Spring beans. It provides out-of-the-box support for discovering common services on Heroku and Cloud Foundry cloud platforms, and it supports custom service definitions through Java Service Provider Interfaces (SPI).

Note
This project is in maintenance mode, in favor of the newer Java CFEnv project. We will continue to release security-related updates but will not address enhancement requests.

Learn more

Build

The project is built with Gradle. The Gradle wrapper allows you to build the project on multiple platforms and even if you do not have Gradle installed; run it in place of the gradle command (as ./gradlew) from the root of the main project directory.

To compile the project and run tests

./gradlew build

To build a JAR

./gradlew jar

To generate Javadoc API documentation

./gradlew api

To list all available tasks

./gradlew tasks

Contributing

Spring Cloud is released under the non-restrictive Apache 2.0 license, and follows a very standard Github development process, using Github tracker for issues and merging pull requests into master. If you want to contribute even something trivial please do not hesitate, but follow the guidelines below.

Sign the Contributor License Agreement

Before we accept a non-trivial patch or pull request we will need you to sign the Contributor License Agreement. Signing the contributor’s agreement does not grant anyone commit rights to the main repository, but it does mean that we can accept your contributions, and you will get an author credit if we do. Active contributors might be asked to join the core team, and given the ability to merge pull requests.

Code of Conduct

This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [email protected].

Code Conventions and Housekeeping

None of these is essential for a pull request, but they will all help. They can also be added after the original pull request but before a merge.

  • Use the Spring Framework code format conventions. If you use Eclipse you can import formatter settings using the eclipse-code-formatter.xml file from the Spring Cloud Build project. If using IntelliJ, you can use the Eclipse Code Formatter Plugin to import the same file.

  • Make sure all new .java files to have a simple Javadoc class comment with at least an @author tag identifying you, and preferably at least a paragraph on what the class is for.

  • Add the ASF license header comment to all new .java files (copy from existing files in the project)

  • Add yourself as an @author to the .java files that you modify substantially (more than cosmetic changes).

  • Add some Javadocs and, if you change the namespace, some XSD doc elements.

  • A few unit tests would help a lot as well — someone has to do it.

  • If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project).

  • When writing a commit message please follow these conventions, if you are fixing an existing issue please add Fixes gh-XXXX at the end of the commit message (where XXXX is the issue number).

spring-cloud-connectors's People

Contributors

chrisjs avatar chrylis avatar fifthposition avatar hosuaby avatar ilayaperumalg avatar jbcpollak avatar jdeppe-pivotal avatar jhiemer avatar jwoodrich avatar jzingler avatar mariobriggs avatar mibo avatar mp911de avatar mrmanz avatar nebhale avatar pidoubleyou avatar ramnivas avatar rmorgan avatar royclarkson avatar scottfrederick avatar soudmaijer avatar spencergibb avatar spikymonkey avatar spring-builds avatar spring-operator avatar viniciusccarvalho avatar wgautier avatar wilkinsona avatar xtreme-allan avatar xyloman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-cloud-connectors's Issues

Duplication in Heroku tests

The Heroku test suite manually re-asserts identical URI parameters on its service definitions instead of having these in a single place. (This is actually common to all URI-based creators, and it would be lovely to have abstract test functionality available to submodules, but I think that would require a separate cloud-test module.)

<cloud:service-scan/> throws error on user-provided service (CloudFoundry v2)

I have a simple Spring app. I've included cloud:service-scan/ in my config. I have a simple user-provided service:

name=jibberish
label=user-provided
tags=[]
credentials={aaa=aaa, bbb=bbb, ccc=ccc}
syslog_drain_url=

When I try to run my app on run.pivotal.io I get:

ERROR: org.springframework.web.servlet.DispatcherServlet - Context initialization failed
org.springframework.cloud.CloudException: Error registering service factory
at org.springframework.cloud.config.CloudServicesScanner.registerServiceBean(CloudServicesScanner.java:97)
at org.springframework.cloud.config.CloudServicesScanner.registerServiceBeans(CloudServicesScanner.java:86)
at org.springframework.cloud.config.CloudServicesScanner.postProcessBeanFactory(CloudServicesScanner.java:79)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:265)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:177)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:609)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:643)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:606)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:657)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:525)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:466)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1088)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5176)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5460)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1120)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1678)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.ClassCastException: org.springframework.cloud.service.BaseServiceInfo cannot be cast to org.springframework.cloud.service.common.RelationalServiceInfo
at org.springframework.cloud.service.relational.DataSourceCreator.create(DataSourceCreator.java:23)
at org.springframework.cloud.Cloud.getServiceConnector(Cloud.java:235)
at org.springframework.cloud.Cloud.getServiceConnector(Cloud.java:128)
at org.springframework.cloud.service.AbstractCloudServiceConnectorFactory.createService(AbstractCloudServiceConnectorFactory.java:93)
at org.springframework.cloud.service.AbstractCloudServiceConnectorFactory.createInstance(AbstractCloudServiceConnectorFactory.java:89)
at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:134)
at org.springframework.cloud.service.AbstractCloudServiceConnectorFactory.afterPropertiesSet(AbstractCloudServiceConnectorFactory.java:84)
at org.springframework.cloud.config.CloudServicesScanner.registerServiceBean(CloudServicesScanner.java:94)
... 29 more

The code seems to want to coerce this user-provided service into a data source of some kind, which causes an error.

Removing cloud:service-scan/ eliminates the error. Unbinding the service also eliminates the error. The cloud:service-scan/ works fine with built-in services, it just objects to this loosely-defined user-provided one.

thx,
k

Allow user-specified connection pool for DataSource

Currently, the DataSource creation logic prefers org.apache.commons.dbcp.BasicDataSource, then its Tomcat equivalent, and then falls back to Spring's SimpleDriverDataSource. We can improve this logic by abstracting pool creation that can also allow utilizing other pools such as BoneCP

CloudException In CloudFactory.getCloud() Method

Why does the method signature not have a throws declaration for the CloudException? I realize that CloudException is a runtime exception and it is not required but it seems like you would want users to always make sure they handle this exception properly.

Bound New Relic service causes application not to start

Currently if a New Relic service is bound to an application using Spring Cloud, the application will fail to start with the following exception:

Caused by: org.springframework.cloud.CloudException: No suitable service info creator found
    at org.springframework.cloud.cloudfoundry.CloudFoundryConnector.getServiceInfo(CloudFoundryConnector.java:66)
    at org.springframework.cloud.cloudfoundry.CloudFoundryConnector.getServiceInfos(CloudFoundryConnector.java:53)
    at org.springframework.cloud.Cloud.getServiceInfos(Cloud.java:86)
    at org.springframework.cloud.Cloud.getServiceInfo(Cloud.java:73)

Allow creation of DataSource without requiring dependency on spring-cloud-connector

Since DataSource and its subclasses are in spring-service-connector, unless user adds the latter as a dependency, creating DataSource connector is not possible. Unlike other connector types (MongoDbFactory), DataSource doesn't have any inherent dependency on Spring. Thus, it should be possible to move its creation in the core iself.

The tricky part is allowing the use of connection pool (which currently uses Spring classes such as BeanWrapper).

Minimum Java version?

It appears but isn't directly discussed in the docs that the minimum Java version for the project is 1.6. I'd love to use StandardCharsets but will deal with that gaping hole in the API for 1.6 if needed.

JDBC URL in PostgresqlServiceInfo isn't directly usable

Currently, the url returned from PostgresqlServiceInfo.getJdbcUrl() isn't directly usable. There are two problems with it.

Incorrect scheme

The current implementation of this method simply prepends the URI from VCAP_SERVICES with jdbc:. The result is something like:

postgres://username:[email protected]:5432/username =>
    jdbc:postgres://username:[email protected]:5432/username

However, as described here, the correct sheme is actually jdbc:postgresql. This can be verified by pushing an app that does something like this:

BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass(Driver.class.getCanonicalName());
dataSource.setJdbcUrl(serviceInfo.getJdbcUrl());
dataSource.setUsername(serviceInfo.getUserName());
dataSource.setPassword(serviceInfo.getPassword());

The output will reflect the problem:

java.sql.SQLException: No suitable driver found for jdbc:postgres://username:[email protected]:5432/username
    at java.sql.DriverManager.getConnection(DriverManager.java:604)
    at java.sql.DriverManager.getConnection(DriverManager.java:221)

Incorrect hostname

The current implementation uses the hostname VCAP_SERVICES without stripping credentials off of it. The postgresql JDBC driver cannot tolerate this.

However, as described here, the correct hostname cannot have credentials attached to it. This can be verified by pushing an app that does something like this:

BoneCPDataSource dataSource = new BoneCPDataSource();
dataSource.setDriverClass(Driver.class.getCanonicalName());
dataSource.setJdbcUrl(serviceInfo.getJdbcUrl().replace(":postgres:", ":postgresql:");
dataSource.setUsername(serviceInfo.getUserName());
dataSource.setPassword(serviceInfo.getPassword());

The output will reflect the problem:

Caused by: java.net.UnknownHostException: username:[email protected]
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:391)
    at java.net.Socket.connect(Socket.java:579)
    at java.net.Socket.connect(Socket.java:528)

Solution

An example solution might look like the following:

String.format("jdbc:postgresql://%s:%d/%s", serviceInfo.getHost(), serviceInfo.getPort(),
    serviceInfo.getUserName());

Exception when connecting to MongoDB

Hi,
I tried to connect to MongoDB today, with the latest release of the MongoDB Driver (2.12.3 against 2.2, Spring Data MongoDB 1.5.4, CF-Service-Release v5 with MongoDB 2.2). During the connection I get an exception, which results in a exception:

com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms
    com.mongodb.BaseCluster.getServer(BaseCluster.java:87)
    com.mongodb.DBTCPConnector.getServer(DBTCPConnector.java:654)
    com.mongodb.DBTCPConnector.access$300(DBTCPConnector.java:39)
    com.mongodb.DBTCPConnector$MyPort.getConnection(DBTCPConnector.java:503)
    com.mongodb.DBTCPConnector$MyPort.get(DBTCPConnector.java:451)
    com.mongodb.DBTCPConnector.authenticate(DBTCPConnector.java:624)
    com.mongodb.DBApiLayer.doAuthenticate(DBApiLayer.java:195)
    com.mongodb.DB.authenticateCommandHelper(DB.java:765)
    com.mongodb.DB.authenticate(DB.java:721)
    org.springframework.data.mongodb.core.MongoDbUtils.doGetDB(MongoDbUtils.java:123)
    org.springframework.data.mongodb.core.MongoDbUtils.getDB(MongoDbUtils.java:81)
    org.springframework.data.mongodb.core.SimpleMongoDbFactory.getDb(SimpleMongoDbFactory.java:145)
    org.springframework.data.mongodb.core.SimpleMongoDbFactory.getDb(SimpleMongoDbFactory.java:134)
    org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.createIndex(MongoPersistentEntityIndexCreator.java:135)
    org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForAndCreateIndexes(MongoPersistentEntityIndexCreator.java:129)
    org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.checkForIndexes(MongoPersistentEntityIndexCreator.java:121)
    org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.onApplicationEvent(MongoPersistentEntityIndexCreator.java:105)
    org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator.onApplicationEvent(MongoPersistentEntityIndexCreator.java:46)
    org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:98)
    org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:333)
    org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:307)
    org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:470)
    org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:427)
    org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:579)
    org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:295)
    org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:470)
    org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:427)
    org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:579)

On my local machine the repositories are running without any issue. Currently digging through the web finding possibly related information. Any suggestions?

Accessing User Provided Services

I am trying to access user provided services in my VCAP_SERVICE environment var. I see the ups connector but that seems to expect the user provided service to just have a URI. In my case I also have a username and password. Is there any other helper classes I can use to access this service?

Add properties-based "local" connector

I'm very interested in using Spring Cloud to configure my application (which I'm planning to push to Cloud Foundry), and it would be extremely convenient to be able to use Spring Cloud to handle development configuration as well. Would you be interested in adding a connector that implemented the connector wiring via some local hand-configured means such as a properties file?

ServiceConnectorCreator docs

The ServiceConnectorCreator interface needs suitable Javadocs on the get methods. I think I understand what they're supposed to return, but it's not specifically stated.

Spring Cloud BOM

I'm glad to see the main Spring projects including BOM POMs now, but I don't know how to create one in Gradle (other than the obvious fragile XML template file). It would be very helpful to have one for Spring Cloud, especially for testing live applications against development versions of SC.

AbstractCloudConnector#getServiceInfos called multiple times

On startup, I notice that getServiceInfos() gets called multiple times; apparently, it gets called once to identify the service names, and then it gets called again to specifically retrieve each service by name. The implementation in AbstractCloudConnector delegates to getServicesData(), which in all the connectors rebuilds the entire cloud context. I think that getServiceInfos() should cache the result before returning; is there a reason not to do this?

support for MongoDB replica sets

MongoDB specifies replica sets using multiple hostname:port pairs in that section of its URI. Spring Data MongoDB does support replica sets, but Spring Cloud Connectors currently hard-maps the incoming service spec onto a URI. I am preparing for a production deployment and would like to point my client at both of my replicas, but the current design may need some major rework to make that happen.

Issue with user provided services and spring-cloud

Hey,

I tried to create a custom service that should be interpreted as a MySQL service. I checked the sources and found out, that the term "mysql" needs to be in the tags array. So this is what I did to create the service:

✗ cf create-service                                 
1: p-mysql , via 
2: p-mysql-custom , via 
3: user-provided , via 
What kind?> 3

Name?> upsi-mysql   

What credential parameters should applications use to connect to this service instance?
(e.g. hostname, port, password)> tags, name, label, credentials

tags> ["mysql"]

name> upsi-mysql              

label> upsi-mysql

credentials> {"hostname":"a.b.c.d","port":3306,"name":"name","username":"user","password":"pass","uri":"mysql://user:[email protected]:3306/schema?reconnect=true","jdbcUrl":"jdbc:mysql://user:[email protected]:3306/schema"}

Creating service upsi-mysql... OK

But this service bound to an app will prevent it from getting staged. What would be the correct way to create a user defined that will be correctly recognized by spring-cloud?

A local spring boot config connector

While playing with spring-cloud and spring boot, I configured my app for cloud foundry, but then when I wanted to run locally, I wanted spring-boot's autoconfigure to kick in and not worry about configuring each service (there are several) to use a different configuration mechanism than boot's (ie LocalConfigConnector.

I created a passthrough connector that extended LocalConfigConnector:

public class NotCFConfigConnector extends LocalConfigConnector {

     private EnvironmentAccessor env = new EnvironmentAccessor();

     @Override
     public boolean isInMatchingCloud() {
          return env.getEnvValue("VCAP_APPLICATION") == null;
     }

     @Override
     protected List<UriBasedServiceData> getServicesData() {
          return Collections.emptyList();
     }
}

Ideally, something that recognizes it is a boot app and perhaps a configurable condition for isInMatchingCloud (I was considering not in a particular spring profile), get's the id from boot configuration and potentially implement getServicesData from boot configuration. I wasn't as concerned about that because of boot auto config support for rabbit/amqp.

I started down this route, but because the config connectors didn't have access to the spring context or environment, I stopped.

Provide connector for Pivotal HD

A sample VCAP_SERVICES:

{
   "p-hd":[
      {
         "name":"phd1",
         "label":"p-hd",
         "tags":[

         ],
         "plan":"Standard",
         "credentials":{
            "hadoop_username":"u295594b875749a",
            "hdfs":{
               "configuration":{
                  "fs.defaultFS":"hdfs://10.68.44.228:8020"
               },
               "directory":"/user/u295594b8757f49a"
            },
            "yarn":{
               "configuration":{
                  "yarn.resourcemanager.address":"10.68.44.229:8032",
                  "mapreduce.framework.name":"yarn",
                  "yarn.resourcemanager.scheduler.address":"10.68.44.229:8030",
                  "mapreduce.job.working.dir":"/user/u295594b8757f49a/work",
                  "yarn.app.mapreduce.am.staging-dir":"/user/u295594b8757f49a/staging"
               }
            },
            "hawq":{
               "uri":"jdbc:postgres://10.68.44.230:5432/default;username=u295594b8757f49a;password=2281f1d7-7d0b-4c79-5ac5-2bdcc811bfde"
            },
            "gemfirexd":{
               "uri":"jdbc:gemfirexd://10.68.44.231:1527/;user=u295594b8757f49a;password=234795ab-322b-43ef-5df6-e90ef74cfa8e"
            }
         }
      }
   ]
}

Refactor CF connector to be URI-based?

I just faceplanted into CF's inability to (AFAICT) set tags on user-provided services, meaning Spring Cloud won't pick them up. However, the MongoDB handler, at least, simply provides credentials in credentials.uri. Any possibility of rolling over to just inspecting those URIs instead of routing them through tag filtering?

MongoDb fails on Cloud Foundry

Looks like the latest MongoDb service on CF does not expose the uri anymore. This field is now called url

             "system_env_json": {
               "VCAP_SERVICES": {
                 "mongodb-2.2": [
                   {
                     "name": "jbehave-reports",
                     "label": "mongodb-2.2",
                     "tags": [
                       "nosql",
                       "document"
                     ],
                     "plan": "default",
                     "credentials": {
                       "hostname": "x",
                       "host": "x",
                       "port": 10002,
                       "username": "6d55a686-de4f-4df1-87e8-8a6052c3cdad",
                       "password": "543caa18-52f8-49ac-ae74-28f91ec32898",
                       "name": "0eb9d144-4851-4f79-9758-f5c97b1b6e45",
                       "db": "db",
                       "url": "mongodb://6d55a686-de4f-4df1-87e8-8a6052c3cdad:543caa18-52f8-49ac-ae74-28f91ec32898@x:10002/db"
                     }
                   }
                 ]
               }

Therefore this fails:

https://github.com/spring-projects/spring-cloud/blob/master/cloudfoundry-connector/src/main/java/org/springframework/cloud/cloudfoundry/MongoServiceInfoCreator.java#L25

We have deployed the latest mongodb from the cf-services-contrib.

Configuring a MongoDB connection

My current code is extending AbstractMongoConfiguration, supplying connection details and registering custom converters to the superclass, which creates the Spring Data objects (specifically the MongoTemplate, MappingMongoConverter, and MongoMappingContext) from the information provided.

How can I convert this to having Spring Cloud inject the MongoDB connection? Should I subclass AbstractCloudConfig, register connectionFactory().mongoDbFactory() as a bean, and then autowire that bean into my AbstractMongoConfiguration as its factory?

Better error message when no service is bound, but <cloud:*> element is specified

It looks like if a cloud:data-source element is present, but no service is bound, the error printed is cryptic and doesn't point to the real issue.

It should have printed an error along the following lines:

Cannot create bean corresponding to <cloud:data-source>; no relational service is bound to the application"

(In this context, database driver was missing, too)

2013-12-04 16:53:18,239 ERROR  [ContextLoader] [main] Context initialization failed 
org.springframework.beans.factory.BeanCreationException: Error registering service factory; nested exception is java.util.NoSuchElementException
at org.springframework.cloud.config.xml.CloudServiceIntroducer.postProcessBeanFactory(AbstractCloudServiceFactoryParser.java:90)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:676)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: java.util.NoSuchElementException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:375)
at java.util.LinkedHashMap$ValueIterator.next(LinkedHashMap.java:388)
at org.springframework.cloud.service.AbstractCloudServiceConnectorFactory.afterPropertiesSet(AbstractCloudServiceConnectorFactory.java:73)
at org.springframework.cloud.config.xml.CloudServiceIntroducer.postProcessBeanFactory(AbstractCloudServiceFactoryParser.java:82)
... 21 more

NPE in StandardUriInfoFactory.createUri

Hi there,
I am currently trying to get a rabbitmq/cloudfoundry sample running. I checked it out from https://github.com/cloudfoundry-samples/rabbitmq-cloudfoundry-samples, did a mvn package and a cf push. Afterwards the log was a follows:

Using manifest file /Users/user/Development/oss/cloudfoundry/rabbitmq-cloudfoundry/spring/manifest.yml

Creating app rabbitmq-spring in org demo / space development as admin...
OK

Creating route rabbitmq-spring-butlerlike-chippie.X.X.X.X.xip.io...
OK

Binding rabbitmq-spring-butlerlike-chippie.X.X.X.X.xip.io to rabbitmq-spring...
OK

Uploading rabbitmq-spring...
Uploading app files from: /Users/user/Development/oss/cloudfoundry/rabbitmq-cloudfoundry/spring/target/rabbitmq-spring-1.0-SNAPSHOT.war
Uploading 7M, 39 files
OK
Binding service cs-rabbitmq to app rabbitmq-spring in org demo / space development as admin...
OK

Starting app rabbitmq-spring in org demo / space development as admin...
OK
-----> Downloaded app package (7.5M)
-----> Java Buildpack source: system
-----> Downloading Open JDK 1.7.0_55 from http://download.run.pivotal.io/openjdk/lucid/x86_64/openjdk-1.7.0_55.tar.gz (3.2s)
       Expanding Open JDK to .java-buildpack/open_jdk (1.5s)
-----> Downloading Spring Auto Reconfiguration 0.8.9 from http://download.run.pivotal.io/auto-reconfiguration/auto-reconfiguration-0.8.9.jar (0.5s)
       Modifying /WEB-INF/web.xml for Auto Reconfiguration
-----> Downloading Tomcat 7.0.53 from http://download.run.pivotal.io/tomcat/tomcat-7.0.53.tar.gz (0.9s)
       Expanding Tomcat to .java-buildpack/tomcat (0.1s)
-----> Downloading Buildpack Tomcat Support 1.1.1 from http://download.run.pivotal.io/tomcat-buildpack-support/tomcat-buildpack-support-1.1.1.jar (0.0s)

-----> Uploading droplet (46M)

0 of 1 instances running, 1 starting
1 of 1 instances running

App started

Showing health and status for app rabbitmq-spring in org demo / space development as admin...
OK

requested state: started
instances: 0/1
usage: 512M x 1 instances
urls: rabbitmq-spring-butlerlike-chippie.X.X.X.X.xip.io

     state     since                    cpu    memory           disk   
#0   running   2014-04-29 09:56:20 PM   0.0%   332.9M of 512M   105.6M of 1G  

But, when I call the app, I get the following exception:

java.lang.NullPointerException
    org.springframework.cloud.util.StandardUriInfoFactory.createUri(StandardUriInfoFactory.java:20)
    org.springframework.cloud.service.UriBasedServiceInfo.<init>(UriBasedServiceInfo.java:26)
    org.springframework.cloud.service.common.RabbitServiceInfo.<init>(RabbitServiceInfo.java:21)
    org.springframework.cloud.cloudfoundry.RabbitServiceInfoCreator.createServiceInfo(RabbitServiceInfoCreator.java:26)
    org.springframework.cloud.cloudfoundry.RabbitServiceInfoCreator.createServiceInfo(RabbitServiceInfoCreator.java:12)
    org.springframework.cloud.AbstractCloudConnector.getServiceInfo(AbstractCloudConnector.java:61)
    org.springframework.cloud.AbstractCloudConnector.getServiceInfos(AbstractCloudConnector.java:40)
    org.springframework.cloud.Cloud.getServiceInfos(Cloud.java:89)
    org.springframework.cloud.Cloud.getServiceInfos(Cloud.java:105)
    org.springframework.cloud.service.AbstractCloudServiceConnectorFactory.afterPropertiesSet(AbstractCloudServiceConnectorFactory.java:77)
    org.springframework.cloud.config.xml.CloudServiceIntroducer.postProcessBeanFactory(AbstractCloudServiceFactoryParser.java:82)
    org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:694)
    org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:684)
    org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
    org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:599)
    org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
    org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:518)
    org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:459)
    org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    javax.servlet.GenericServlet.init(GenericServlet.java:158)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
    java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    java.lang.Thread.run(Thread.java:745)

This makes me wonder, cause the service instances seem to have a uri. As can be seen here:

...
 "entity": {
              "app_guid": "25c1f438-4a3b-492e-ad3e-c4aa1bdcca1a",
              "service_instance_guid": "4028160a-4671-43d6-91a6-7b46c528a53e",
              "credentials": {
                "name": "6c4fefbb-8eb4-43a8-bcb1-464c5d8df8e6",
                "hostname": "172.24.100.141",
                "host": "172.24.100.141",
                "port": 15001,
                "admin_port": 25001,
                "vhost": "v3cf7fb9e401d4b298e5b591356436d14",
                "username": "uZgv8BVGa0Uxz",
                "user": "uZgv8BVGa0Uxz",
                "password":"[PRIVATE DATA HIDDEN]",
                "pass": "pyfNeGLeVdUdQ",
                "url": "amqp://uZgv8BVGa0Uxz:[email protected]:15001/v3cf7fb9e401d4b298e5b591356436d14"
              },

...

My configuration for rabbit looks like this:

...
<!-- Obtain a connection to the RabbitMQ via cloudfoundry-runtime: -->
    <cloud:rabbit-connection-factory id="connectionFactory"/>

    <!-- Set up the AmqpTemplate/RabbitTemplate: -->
    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>

    <!-- Request that queues, exchanges and bindings be automatically
         declared on the broker: -->
    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- Declare the "messages" queue: -->
    <rabbit:queue name="messages" durable="true"/>
..

Son any idea what's wrong here? CF Build is the latest, as well as for services contrib. CLI is 6.1 and Spring is 3.2.

Cannot create postgres DataSource on CloudFoundry

My app does this ("postgresql" is the name of the service instance), using spring-cloud 0.9.1:

    @Bean
    @Profile("cloud")
    public DataSource dataSource() {
        CloudFactory cloudFactory = new CloudFactory();
        Cloud cloud = cloudFactory.getCloud();
        return cloud.getServiceConnector("postgresql", DataSource.class, null);
    }

and I see this:

Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class 'org.postgresql.Driver' for connect URL 'jdbc:postgres://wftjxbes:[email protected]:5432/wftjxbes'
    at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1452)
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
    at demo.Application.run(Application.java:76)
    at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:495)
    ... 10 more
Caused by: java.sql.SQLException: No suitable driver
    at java.sql.DriverManager.getDriver(DriverManager.java:289)
    at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1437)
    ... 14 more

I think Postgresql does not allow the user credentials embedded in the URL. Is that the problem?

WARN logs on startup (looks alarming - should I care?)

These logs on startup are distracting and actually I have no idea if it's important or not. If it isn't then maybe they should be at DEBUG?

2013-10-16 16:21:22.118  WARN 31 --- [           main] .s.c.u.ServiceLoaderWithExceptionControl : Failed to load java.util.ServiceConfigurationError: org.springframework.cloud.service.ServiceConnectorCreator: Provider org.springframework.cloud.service.keyval.RedisConnectionFactoryCreator could not be instantiated: java.lang.NoClassDefFoundError: org/springframework/data/redis/connection/RedisConnectionFactory
2013-10-16 16:21:22.120  WARN 31 --- [           main] .s.c.u.ServiceLoaderWithExceptionControl : Failed to load java.util.ServiceConfigurationError: org.springframework.cloud.service.ServiceConnectorCreator: Provider org.springframework.cloud.service.document.MongoDbFactoryCreator could not be instantiated: java.lang.NoClassDefFoundError: com/mongodb/MongoException
2013-10-16 16:21:22.122  WARN 31 --- [           main] .s.c.u.ServiceLoaderWithExceptionControl : Failed to load java.util.ServiceConfigurationError: org.springframework.cloud.service.ServiceConnectorCreator: Provider org.springframework.cloud.service.messaging.RabbitConnectionFactoryCreator could not be instantiated: java.lang.NoClassDefFoundError: org/springframework/amqp/rabbit/connection/ConnectionFactory

Expose MongoClient as a bean

Some of the Spring infrastructure, especially MongoDataAutoConfiguration, expects a bean of type Mongo to be registered. The MongoDbFactoryCreator creates a MongoClient (extends Mongo) instance along the way to creating the MongoDbFactory but does not expose it, causing the autoconfiguration to fail and abort container startup.

Inconsistent terminology for Heroku App ID

The current code uses SPRING_CLOUD_APP_NAME to identify an application name from within Heroku, but the API refers to the value in question as appId(). Keep as a wart or breaking-change to a consistent SPRING_CLOUD_APP_ID?

Note that the way I determine whether the local connector should activate is to look for spring.cloud.appId; if we extend that to an environment scan, the values would semantically mean the same thing, but the current logic would get a false-positive on the local connector, so that would need to be addressed somehow.

@ServiceScan -> @CloudScan

This is a breaking change, but the @ServiceScan annotation is extremely generic, providing little clue as to what "services" are involved and inviting collisions from other Things That Could Scan For Services.

You had erroneously mentioned @CloudScan in another issue; this would be a much clearer annotation. Perhaps bridge it as a meta-annotation and deprecate @ServiceScan?

How ServiceInfoCreators Work

I am trying to use Spring Cloud within a Spring Boot application and I am deploying this to BlueMix. BlueMix has a an ElephantSQL and Clear DB as services in its catalog. When I bind either of these services to my Spring Boot application and call connectionFactory().dataSource() in my AbstractCloudConfig implementation I am getting an exception saying " No unique service matching interface javax.sql.DataSource found. Expected 1, found 0". After reading the code in CloudFoundryServiceInfoCreator.accept it looks like it will look for whatever tag name is passed into the constructor in a property called tags in the service details or it will look at the service label to see if it begins with the tag. If neither of these are true for the ElephantSQL and Clear DB services, could this result in the error I am seeing?

No suitable ServiceConnectorCreator found

I am using the Cloud.getServiceConnector API to get an instance of MongoServiceInfo in a non-spring app deployed to CF but the API is throwing an exception saying no suitable ServiceConnectorCreator found. When I call cloud.getServiceInfo() I see the service in the list with the correct id and I can cast it to an an instance of MongoServiceInfo. Any idea why I would be getting this error?

Dependencies marked as optional aren't

The dependencies on spring-rabbit, spring-data-mongodb and spring-data-redis are marked as optional, but AbstractCloudConfig has a hard linker dependency on them. It might be possible to do some trickery like Spring Boot does with nested classes and conditions that look for the class, but in the meantime, it is probably easiest to remove the "optional".

ServiceLabel docs

I don't understand what these are for. Something to do with structured CF service definitions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.