I just got a new PC last week. So I setup my working environment as usual in Windows 10 with the latest Windows Docker Desktop. Then created a very simple spring boot REST service just to say hello, created the image with Spring boot Buildpacks 3 days ago, it worked fine with port mapping “docker run -p 8090:8080 davy/myapp”. This image is working well even today: I can access my application by “http://localhost:8090/sayHello” even today.
the working image
So, I started to build my real application and completed some functionalities. I wanted to test my app and created a new image by using spring boot Buildpacks.
Now I got a big problem: I cannot not access the application running in the container by port mapping with port mapping “docker run -p 8090:8080 davy/myapp” any more by “http://localhost:8090/sayHello”. It got an error page said "localhost did not send any data"
cannot send data image
Then I got my container IP by “docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 548e29f46ca7”, which displayed as “172.17.0.2/”. So I tried http://172.17.0.2:8090/sayHello. Now I got a timeout after waiting for some time I got "172.17.0.2 took too long to respond":
timeout image
I did not see any difference in the ports binding: both are 0.0.0.0:8090->8080/tcp
port binding for 2 images
I re-built the image several times by using Spring boot Buildpacks, 1 time Dockerfile and docker-compose.yml, and I cannot make the container like the old container any more.
I also tried “docker run -p 8088:8080 davyhu/myapp -m http.server --bind 0.0.0.0”, but got the same result: cannot access app by localhost, and IP timeout.
Thanks in advance for the helps!
Here are some more information:
config in pom.xml for buildpacks (no change for both versions in the pom.xml):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>davyhu/${project.artifactId}</name>
</image>
</configuration>
</plugin>
</plugins>
</build>
PDFController.java
public class PdfGenerationController {
private static final Logger logger = LoggerFactory.getLogger(PdfGenerationController.class);
private static final SimpleDateFormat DateFormatterIn1 = new SimpleDateFormat("yyyy-MM-dd");
//private static final SimpleDateFormat DateFormatterIn2 = new SimpleDateFormat("dd/MM/yyyy");
private static final SimpleDateFormat DateFormatterOut = new SimpleDateFormat("dd/MM/yyyy");
private static final SimpleDateFormat DateFormatterIn2 = new SimpleDateFormat("yyyy-MM-dd");
//private static final SimpleDateFormat DateFormatterOut = new SimpleDateFormat("yyyy-MM-dd");
#Autowired
private ResourceBundleMessageSource source;
#Value("${pdf.title}")
private static String pdfTitle;
#Value("${pdf.footerText1}")
private static String pdfFooterText1;
#CrossOrigin(origins = "http://localhost:4200")
#PostMapping("/getPdf")
public ResponseEntity<byte[]> getPDF(
#RequestHeader(name = "Accept-Language", required = true) final Locale locale,
#RequestBody String jsonInput) {
logger.info("myCustomerDetails() method started");
logger.info(jsonInput);
logger.info("locale = {}", locale);
JSONObject data = new JSONObject(jsonInput);
byte[] pdfFile = null;
ResponseEntity<byte[]> response = null;
HttpHeaders headers = new HttpHeaders();
try {
pdfFile = new PdfGenertor().generatePDF(data,locale);
}catch (Exception e) {
e.printStackTrace();
response = new ResponseEntity<>(null, headers, HttpStatus.METHOD_FAILURE);
}
headers.setContentType(MediaType.APPLICATION_PDF);
String filename = "fro_soa_form.pdf";
headers.setContentDispositionFormData(filename, filename);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
response = new ResponseEntity<>(pdfFile, headers, HttpStatus.OK);
return response;
}
private String formatDate(SimpleDateFormat format, String str) {
try {
Date date = format.parse(str);
return DateFormatterOut.format(date);
} catch (Exception e) {
return "";
}
}
#GetMapping("/sayHello")
public String sayHello() {
return "Hello";
}
}
It the code worked fine in eclipse with postman (PDF displayed with Jason input and header accepted language).
first and second image are all build with "mvn spring-boot:build-image".
If anything I need to post, please let mw know.
Thanks!
Dockerfile:
FROM openjdk:11-slim as build
MAINTAINER xxxx.ca
COPY target/fro_soa_backend-0.0.1-SNAPSHOT.jar fro_soa_backend-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/fro_soa_backend-0.0.1-SNAPSHOT.jar"]
Well just to tell you that 172.17..0.2 is the ip container so it can't be reached out of the container, it's created from the container to get access from other services or micro-services.
It seems that your app config isn't proprely display to this port, means that your application isn't on 8080 port that's why it gets you empty response, when you added your fonctionalities, you need to use your Dockerfile and expose your application in 8080.
FROM <image_name>
EXPOSE 8080
I cannot figure it out what's wrong. So I just created a new workspace from scratch, import the code, rebuilt the application into Docker with Dockerfile, then the Port mapping get working again.
Now my front Angular and backend Spring boot Apps can communicate on localhost.
Related
Quick summary: How can I change the default port of the minio client running in my test container?
I want to use minio as a testcontainer in my application which already working when I start it locally. here is the codesnippet I use to run the testcontainer:
public class MinioContainer extends GenericContainer<MinioContainer> {
private static final int DEFAULT_PORT = 9000;
private static final String DEFAULT_IMAGE = "/minio/minio";
private static final String DEFAULT_TAG = "latest";
private static final String MINIO_ACCESS_KEY = "MINIO_ACCESS_KEY";
private static final String MINIO_SECRET_KEY = "MINIO_SECRET_KEY";
private static final String DEFAULT_STORAGE_DIRECTORY = "/data";
private static final String HEALTH_ENDPOINT = "/minio/health/ready";
public MinioContainer() {
this(DEFAULT_IMAGE + ":" + DEFAULT_TAG);
}
public MinioContainer(String image) {
super(image == null ? DEFAULT_IMAGE + ":" + DEFAULT_TAG : image);
Network network = Network.newNetwork();
withNetwork(network);
withNetworkAliases("minio-" + Base58.randomString(6));
addExposedPort(DEFAULT_PORT);
withEnv(MINIO_ACCESS_KEY, "access_key");
withEnv(MINIO_SECRET_KEY, "secret_key");
withCommand("server", DEFAULT_STORAGE_DIRECTORY);
setWaitStrategy(new HttpWaitStrategy()
.forPort(DEFAULT_PORT)
.forPath(HEALTH_ENDPOINT)
.withStartupTimeout(Duration.ofMinutes(1)));
}
public String getHostAddress() {
return getHost() + ":" + getMappedPort(DEFAULT_PORT);
}
}
As soon as I deploy this on our cluster, where also an minio container is running at port 9000, it shows this error message in the console:
io.minio.errors.ErrorResponseException: The Access Key Id you provided does not exist in our records.
at some.package.MinioTest.setup(MinioTest.java:58)
In my test i am running a SpringBootTest using this container and injecting my minio client. I also configured a test application yaml so I can run my test with an active test profile. The error happens on following code snippet:
private final String BUCKET = "bucket";
....
#BeforeEach
void setup() {
boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(BUCKET).build());
...
}
Is there a way to change the DEFAULT_PORT on my MinioContainer so it is not the same port as the minio container already running on my cluster? I am not able to get my tests running on our pipeline because of this issue, which is only happening on our cluster.
As soon as I change the DEFAULT_PORT to something different than 9000 on my MinioContainer, the Container stops working because it is not able to find the HEALTH_ENDPOINT and therefor the whole container just stops working.
I hope I explained my problem clear enough. If not please tell me so I can try to explain it clearer. I am already completely frustrated with this issue.
BR
Null
I found the solution for my problem. Minio supports the following command:
"server /data --address :9100"
Now I was able to generate my testcontainer now like this:
public static GenericContainer<?> minioContainer = new GenericContainer<>(MINIO_IMAGE)
.withCommand("server /data --address :9100")
.withExposedPorts(9100);
Now the MinioContainer in my Test runs with Port 9100.
Hopefully I was able to help someone else with this issue.
I just deployed my first microservice. My microservice is working fine. All routes are working. But the service class inside the microservice is not working properly. The service class is not reading data from the CSV file.
Below is the code I am using to read data from CSV file.
public class ReadCsvUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(ReadCsvUtil.class);
public List<String[]> readData() throws IOException {
String file = ".\\src\\main\\resources\\pensioners.csv";
List<String[]> content = new ArrayList<>();
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
String line = "";
while ((line = br.readLine()) != null) {
content.add(line.split(","));
}
} catch (FileNotFoundException e) {
LOGGER.debug(e.getMessage());
}
return content;
}
}
The service class invokes the above function to get details of all the people.
The above code is working fine on my desktop and I am able to get details but code is not working on AWS. Also, I tried to remove the CSV and manually enter the values and it's working in AWS. So I am 99% sure there is some problem in reading the CSV files.
Is there anyway I can fix this?
If the path to the file one directory up, instead of
String file = ".\\src\\main\\resources\\pensioners.csv";
try,
String file = "..\src\main\resources\pensioners.csv";
I presume the AWS sever is ubuntu and your local is windows OS.
Below is code for copy files(any type of file) from remote machine or any other machine which is in our LAN. How to automatically copy files Using Apche Camel.
I want to copy images, so any method to copy only images.
I implement this in spring.
final String sourceFolder = "ftp:172.30.83.119\\D:MyCLone\\WSIMS\\images?username=shailesh.bhad&password=Password2";
final String destinationFolder = "file:D:\\outbox";
final CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from(sourceFolder).to(destinationFolder);
}
});
camelContext.start();
Thread.sleep(30000);
camelContext.stop();
}
See the FTP example
http://camel.apache.org/ftp-example.html
And then insted of sending to another FTP server, you can change the url to use the file component so it can store the files in your LAN
And see also this FAQ how to keep a Java JVM running
http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html
Can anyone tell why this didn't work? The code works great when I run it from my unit tests. Security gets setup perfectly and our service works great just like I expect.
However, when I deployed it to our application server (weblogic), my service fails every time because my tokens are not getting setup. I got it working by setting up the tokens every time my send(final ServiceAPInvoice invoice) method gets called.
My question is why does the tokens not get setup by my constructor when this is deployed in our Weblogic environment? What causes this issue? OAuthSecurityContextHolder is a static class. Is that playing into my issue? Will I still run into issues if I setup the tokens each time my send method is called? I haven't noticed any issues yet but have not done any load testing
I am using Spring's OAuthRestTemplate (1.0) and I have non-expiring tokens that I need to setup.
Here is where the magic happens. I had to rename the code slightly to make it generic so hopefully I don't have any typos:
public class ServiceRestTemplate {
private final OAuthRestTemplate serviceOAuthRestTemplate;
private final String apUri;
private final String arUri;
private final String tokenValue;
private final String tokenSecret;
public ServiceRestTemplate(final OAuthRestTemplate serviceOAuthRestTemplate,
final String apUri,
final String arUri,
final String tokenValue,
final String tokenSecret) {
this.serviceOAuthRestTemplate = serviceOAuthRestTemplate;
this.apUri = apUri;
this.arUri = arUri;
this.tokenSecret = tokenSecret;
this.tokenValue = tokenValue;
setContext(tokenValue, tokenSecret); // I expected this to be enough to setup my tokens 1 time
}
private void setContext(final String tokenValue, final String tokenSecret) {
final OAuthConsumerToken accessToken = new OAuthConsumerToken();
accessToken.setAccessToken(true);
accessToken.setResourceId(serviceOAuthRestTemplate.getResource().getId());
accessToken.setValue(tokenValue);
accessToken.setSecret(tokenSecret);
final OAuthSecurityContextImpl securityContext = new OAuthSecurityContextImpl();
if (securityContext.getAccessTokens() == null) {
securityContext.setAccessTokens(new HashMap<String, OAuthConsumerToken>());
}
if (!securityContext.getAccessTokens().containsKey(accessToken.getResourceId())) {
securityContext.getAccessTokens().put(accessToken.getResourceId(), accessToken);
}
OAuthSecurityContextHolder.setContext(securityContext);
}
#Override
public ServiceWebResponse send(final ServiceAPInvoice invoice) {
setContext(this.tokenValue, this.tokenSecret); // This line of code is the workaround to fixed my issue.
final ServiceWebResponse serviceResponse = serviceOAuthRestTemplate.postForObject(apUri,
invoice,
ServiceWebResponse.class);
return serviceResponse;
}
}
We have a business functionality which is exposed as a Remote EJB. We shared the remote interface with the client. Below is the Remote interface that we shared.
public interface EmployeeRemoteEJB {
public Output saveEmployee(Input input);
}
public Output extends BaseObj{
private static final long serialVersionUID = -7096731222829800554L;
//some fields are there
}
public Input extends BaseObj{
private static final long serialVersionUID = -70967312228423800554L;
//some fields
}
public BaseObj implements Serializable{
}
Now Input class and Output class has some fields, which also extends from BaseObj and has a generated SerialVersion UID.
Now we have deployed this EJB on WebSphere Application Server 7.0. The Remote invocation of EJB works fine. It breaks when we do a deployment of the Client web app which calls the EJB or the
web application which has the EJB. We get the ClassCastException that the
com.test.ejb._EmployeeRemoteEJB_Stub incompatible with com.test.ejb.EmployeeRemoteEJB
When we restart the applications, it starts working again.
This is how we invoke the Remote EJB
//This JNDI name is configured for the remote EJB.
String REMOTE_LOOKUP_KEY = "empremotesvc";
String JNDI_PROVIDER_URL = "iiop://10.222.232.111:2809";
Properties props = new Properties();
props.put( Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
props.put( Context.PROVIDER_URL, JNDI_PROVIDER_URL );
Object lobj;
InitialContext ctx;
try{
ctx = new InitialContext( props );
lobj = ctx.lookup( REMOTE_LOOKUP_KEY );
EmployeeRemoteEJB empObjRemote = (EmployeeRemoteEJB) lobj;
return empObjRemote ;
}
catch( NamingException e ){
e.printStackTrace();
}
Can someone please let me know what is causing this issue? Please let me know if you need any further details.
You need to call PortableRemoteObject.narrow:
lobj = ctx.lookup( REMOTE_LOOKUP_KEY );
EmployeeRemoteEJB empObjRemote = (EmployeeRemoteEJB)
PortableRemoteObject.narrow(lobj, EmployeeRemoteEJB.class);
The problem does not always occur because JNDI caches resolved IOR-to-stub using the class loader of first client app to look up the EJB, so the first application to use the target EJB will work, but the second and subsequent will not unless they use PortableRemoteObject.narrow.