Skip to content

Commit df15c5b

Browse files
YARN-11877. Resolve JAXB IllegalAnnotation issue in TimelineEntity with Jersey 2.x. (#8018)
* YARN-11877. Resolve JAXB IllegalAnnotation issue in TimelineEntity with Jersey 2.x. Co-authored-by: Laszlo Bodor <bodorlaszlo0202@gmail.com> Reviewed-by: Ayush Saxena <ayushsaxena@apache.org> Signed-off-by: Shilun Fan <slfan1989@apache.org>
1 parent 2adc485 commit df15c5b

3 files changed

Lines changed: 214 additions & 0 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.yarn.api.records.timeline.reader;
19+
20+
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import org.apache.hadoop.yarn.api.records.timeline.TimelineEntity;
22+
23+
import javax.ws.rs.Consumes;
24+
import javax.ws.rs.WebApplicationException;
25+
import javax.ws.rs.core.MediaType;
26+
import javax.ws.rs.core.MultivaluedMap;
27+
import javax.ws.rs.ext.MessageBodyReader;
28+
import javax.ws.rs.ext.Provider;
29+
import java.io.IOException;
30+
import java.io.InputStream;
31+
import java.lang.annotation.Annotation;
32+
import java.lang.reflect.Type;
33+
34+
/**
35+
* We have defined a dedicated Reader for TimelineEntity,
36+
* aimed at adapting to the Jersey2 framework
37+
* to ensure that JSON can be converted into TimelineEntity.
38+
*/
39+
@Provider
40+
@Consumes(MediaType.APPLICATION_JSON)
41+
public class TimelineEntityReader implements MessageBodyReader<TimelineEntity> {
42+
43+
private ObjectMapper objectMapper = new ObjectMapper();
44+
45+
@Override
46+
public boolean isReadable(Class<?> type, Type genericType,
47+
Annotation[] annotations, MediaType mediaType) {
48+
return type == TimelineEntity.class;
49+
}
50+
51+
@Override
52+
public TimelineEntity readFrom(Class<TimelineEntity> type, Type genericType,
53+
Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
54+
InputStream entityStream) throws IOException, WebApplicationException {
55+
return objectMapper.readValue(entityStream, TimelineEntity.class);
56+
}
57+
}

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryServer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
import org.apache.hadoop.yarn.YarnUncaughtExceptionHandler;
4242
import org.apache.hadoop.yarn.api.ApplicationBaseProtocol;
4343
import org.apache.hadoop.yarn.api.records.timeline.reader.TimelineDomainReader;
44+
import org.apache.hadoop.yarn.api.records.timeline.reader.TimelineEntityReader;
4445
import org.apache.hadoop.yarn.api.records.timeline.reader.TimelinePutResponseReader;
4546
import org.apache.hadoop.yarn.api.records.timeline.reader.TimelineEntitiesReader;
47+
import org.apache.hadoop.yarn.api.records.timeline.writer.TimelineEntityWriter;
4648
import org.apache.hadoop.yarn.api.records.timeline.writer.TimelineEntitiesWriter;
4749
import org.apache.hadoop.yarn.conf.YarnConfiguration;
4850
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
@@ -363,6 +365,8 @@ protected ResourceConfig configure() {
363365
config.register(AHSWebServices.class);
364366
config.register(TimelineEntitiesWriter.class);
365367
config.register(TimelineEntitiesReader.class);
368+
config.register(TimelineEntityReader.class);
369+
config.register(TimelineEntityWriter.class);
366370
config.register(TimelineDomainReader.class);
367371
config.register(TimelinePutResponseReader.class);
368372
config.register(new JerseyBinder());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.yarn.server.applicationhistoryservice;
20+
21+
import java.io.IOException;
22+
23+
import javax.ws.rs.client.Client;
24+
import javax.ws.rs.client.ClientBuilder;
25+
import javax.ws.rs.client.WebTarget;
26+
import javax.ws.rs.core.MediaType;
27+
import javax.ws.rs.core.Response;
28+
29+
import org.junit.jupiter.api.AfterAll;
30+
import org.junit.jupiter.api.BeforeAll;
31+
import org.junit.jupiter.api.Test;
32+
import org.slf4j.Logger;
33+
import org.slf4j.LoggerFactory;
34+
35+
import org.apache.hadoop.conf.Configuration;
36+
import org.apache.hadoop.yarn.api.records.timeline.TimelineEntity;
37+
import org.apache.hadoop.yarn.api.records.timeline.TimelinePutResponse;
38+
import org.apache.hadoop.yarn.api.records.timeline.reader.TimelineEntityReader;
39+
import org.apache.hadoop.yarn.client.api.TimelineClient;
40+
import org.apache.hadoop.yarn.conf.YarnConfiguration;
41+
import org.apache.hadoop.yarn.exceptions.YarnException;
42+
import org.apache.hadoop.yarn.server.timeline.MemoryTimelineStore;
43+
import org.apache.hadoop.yarn.server.timeline.TimelineStore;
44+
45+
import static org.apache.hadoop.yarn.conf.YarnConfiguration.TIMELINE_HTTP_AUTH_PREFIX;
46+
import static org.junit.jupiter.api.Assertions.assertEquals;
47+
import static org.junit.jupiter.api.Assertions.assertNotNull;
48+
import static org.junit.jupiter.api.Assertions.assertTrue;
49+
import static org.junit.jupiter.api.Assertions.fail;
50+
51+
public class TestTimelineServerRequests {
52+
private static final Logger LOG =
53+
LoggerFactory.getLogger(TestTimelineServerRequests.class);
54+
55+
private static final String HOST = "localhost";
56+
private static final String TIMELINE_SERVICE_WEBAPP_ADDRESS = HOST + ":0";
57+
private static final String ENTITY_TYPE = "TEST_ENTITY_TYPE";
58+
private static final String ENTITY_ID = "test_entity_1";
59+
private static ApplicationHistoryServer testTimelineServer;
60+
private static Configuration conf;
61+
62+
@BeforeAll
63+
public static void setup() {
64+
try {
65+
testTimelineServer = new ApplicationHistoryServer();
66+
conf = new Configuration(false);
67+
conf.setStrings(TIMELINE_HTTP_AUTH_PREFIX + "type", "simple");
68+
69+
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_ENABLED, true);
70+
conf.setClass(YarnConfiguration.TIMELINE_SERVICE_STORE,
71+
MemoryTimelineStore.class, TimelineStore.class);
72+
conf.set(YarnConfiguration.TIMELINE_SERVICE_WEBAPP_ADDRESS, TIMELINE_SERVICE_WEBAPP_ADDRESS);
73+
conf.setInt(YarnConfiguration.TIMELINE_SERVICE_CLIENT_MAX_RETRIES, 1);
74+
75+
testTimelineServer.init(conf);
76+
testTimelineServer.start();
77+
} catch (Exception e) {
78+
LOG.error("Failed to setup TimelineServer", e);
79+
fail("Couldn't setup TimelineServer");
80+
}
81+
}
82+
83+
@AfterAll
84+
public static void tearDown() throws Exception {
85+
if (testTimelineServer != null) {
86+
testTimelineServer.stop();
87+
}
88+
}
89+
90+
@Test
91+
void testPutAndGetTimelineEntity() throws Exception {
92+
putEntity();
93+
getEntity();
94+
}
95+
96+
private void putEntity() throws IOException, YarnException {
97+
TimelineClient client = createTimelineClient();
98+
try {
99+
TimelineEntity entityToStore = new TimelineEntity();
100+
entityToStore.setEntityType(ENTITY_TYPE);
101+
entityToStore.setEntityId(ENTITY_ID);
102+
entityToStore.setStartTime(System.currentTimeMillis());
103+
TimelinePutResponse putResponse = client.putEntities(entityToStore);
104+
assertTrue(putResponse.getErrors().isEmpty(),
105+
String.format("There were some errors in the putResponse: %s",
106+
putResponse.getErrors()));
107+
TimelineEntity entityToRead =
108+
testTimelineServer.getTimelineStore().getEntity(ENTITY_ID, ENTITY_TYPE,
109+
null);
110+
assertNotNull(entityToRead, "Timeline entity should not be null");
111+
} finally {
112+
client.stop();
113+
}
114+
}
115+
116+
private TimelineClient createTimelineClient() {
117+
TimelineClient client = TimelineClient.createTimelineClient();
118+
client.init(conf);
119+
client.start();
120+
return client;
121+
}
122+
123+
private void getEntity() {
124+
String appUrl = String.format("http://%s:%d/ws/v1/timeline/%s/%s?user.name=foo",
125+
HOST, testTimelineServer.getPort(), ENTITY_TYPE, ENTITY_ID);
126+
LOG.info("Getting timeline entity: {}", appUrl);
127+
128+
Client client = ClientBuilder.newClient();
129+
try {
130+
client.register(TimelineEntityReader.class);
131+
WebTarget target = client.target(appUrl);
132+
133+
Response response =
134+
target.request(MediaType.APPLICATION_JSON).get(Response.class);
135+
try {
136+
assertEquals(200, response.getStatus());
137+
assertTrue(MediaType.APPLICATION_JSON_TYPE.isCompatible(
138+
response.getMediaType()));
139+
140+
TimelineEntity entity = response.readEntity(TimelineEntity.class);
141+
assertNotNull(entity, "Timeline entity should not be null");
142+
assertEquals(ENTITY_TYPE, entity.getEntityType());
143+
assertEquals(ENTITY_ID, entity.getEntityId());
144+
assertNotNull(entity.getStartTime(),
145+
"Timeline entity start time should not be null");
146+
} finally {
147+
response.close();
148+
}
149+
} finally {
150+
client.close();
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)