I know how to pretty print the JSONby default, but I want to give the choice up to the user. Thats why I want to make it configureable via QueryParam.
This should pretty print json (if not given default is false):
...test123/res123?pretty=T
...test123/res123?pretty=True
...test123/res123?pretty=t
...test123/res123?pretty=true
Does someone have a good idea to do this without copying the same code to thousands resources? Should I do this with a messagebody writer? Or outgoing filter?
The solution (Thanks to Alexey Gavrilov for the hint):
import java.io.IOException;
import javax.ws.rs.core.MultivaluedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.jaxrs.cfg.EndpointConfigBase;
import com.fasterxml.jackson.jaxrs.cfg.ObjectWriterModifier;
public class IndentingModifier extends ObjectWriterModifier {
private static final Logger LOG = LoggerFactory.getLogger(IndentingModifier.class);
public static boolean doIndent = false;
public final Boolean _indent;
public IndentingModifier() {
this(null);
}
public IndentingModifier(
Boolean indent) {
_indent = indent;
}
#Override
public ObjectWriter modify(
EndpointConfigBase<?> endpoint,
MultivaluedMap<String, Object> responseHeaders,
Object valueToWrite,
ObjectWriter w,
JsonGenerator g) throws IOException {
if (_indent != null) {
if (_indent.booleanValue()) {
LOG.debug("Using default pretty printer, because ident is null.");
g.useDefaultPrettyPrinter();
}
} else {
if (doIndent) {
LOG.debug("Using default pretty printer, because ident is true.");
g.useDefaultPrettyPrinter();
}
}
return w;
}
}
And the Container Filter:
import java.io.IOException;
import java.util.List;
import java.util.Map.Entry;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.jaxrs.cfg.ObjectWriterInjector;
#Provider
public class JsonPrettryPrintQueryParamContainerResponseFilter implements javax.ws.rs.container.ContainerResponseFilter {
private static final Logger LOG = LoggerFactory.getLogger(JsonPrettryPrintQueryParamContainerResponseFilter.class);
private static final String QUERY_PARAM_PRETTY = "pretty";
private static final String QUERY_PARAM_T = "t";
private static final String QUERY_PARAM_TRUE = "true";
private static final String QUERY_PARAM_F = "f";
private static final String QUERY_PARAM_False = "false";
#Override
public void filter(
ContainerRequestContext requestContext,
ContainerResponseContext responseContext) throws IOException {
MultivaluedMap<String, String> queryParams = requestContext.getUriInfo().getQueryParameters();
for (Entry<String, List<String>> queryEntry : queryParams.entrySet()) {
if (queryEntry.getKey().equalsIgnoreCase(QUERY_PARAM_PRETTY)) {
String valueOfLastQueryParamIndex = queryEntry.getValue().get(queryEntry.getValue().size() - 1);
LOG.debug(String.format("Found queryPram '%s' with value '%s'.", queryEntry.getKey(),
valueOfLastQueryParamIndex));
switch (valueOfLastQueryParamIndex.toLowerCase()) {
case QUERY_PARAM_T:
ObjectWriterInjector.set(new IndentingModifier(true));
break;
case QUERY_PARAM_TRUE:
ObjectWriterInjector.set(new IndentingModifier(true));
break;
case QUERY_PARAM_F:
ObjectWriterInjector.set(new IndentingModifier(false));
break;
case QUERY_PARAM_False:
ObjectWriterInjector.set(new IndentingModifier(false));
break;
default:
break;
}
break;
}
}
}
}
In extended application class run():
environment.jersey().register(JsonPrettryPrintQueryParamContainerResponseFilter.class);
You can use ObjectWriterInjector and ObjectWriterModifier to customize the object writer in the resource method depending on the query parameter.
Take a look at this code sample from the Jackson JAX-RS provider repository.
Related
I'm getting an error with StreamIdentifier when trying to use MultiStreamTracker in a kinesis consumer application.
java.lang.IllegalArgumentException: Unable to deserialize StreamIdentifier from first-stream-name
What is causing this error? I can't find a good example of using the tracker with kinesis.
The stream name works when using a consumer with a single stream so I'm not sure what is happening. It looks like the consumer is trying to parse the accountId and streamCreationEpoch. But when I create the identifiers I am using the singleStreamInstance method. Is the stream name required to have these values? They appear to be optional from the code.
This test is part of a complete example on github.
package kinesis.localstack.example;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.amazonaws.services.kinesis.producer.KinesisProducer;
import com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
import software.amazon.kinesis.common.ConfigsBuilder;
import software.amazon.kinesis.common.InitialPositionInStream;
import software.amazon.kinesis.common.InitialPositionInStreamExtended;
import software.amazon.kinesis.common.KinesisClientUtil;
import software.amazon.kinesis.common.StreamConfig;
import software.amazon.kinesis.common.StreamIdentifier;
import software.amazon.kinesis.coordinator.Scheduler;
import software.amazon.kinesis.exceptions.InvalidStateException;
import software.amazon.kinesis.exceptions.ShutdownException;
import software.amazon.kinesis.lifecycle.events.InitializationInput;
import software.amazon.kinesis.lifecycle.events.LeaseLostInput;
import software.amazon.kinesis.lifecycle.events.ProcessRecordsInput;
import software.amazon.kinesis.lifecycle.events.ShardEndedInput;
import software.amazon.kinesis.lifecycle.events.ShutdownRequestedInput;
import software.amazon.kinesis.processor.FormerStreamsLeasesDeletionStrategy;
import software.amazon.kinesis.processor.FormerStreamsLeasesDeletionStrategy.NoLeaseDeletionStrategy;
import software.amazon.kinesis.processor.MultiStreamTracker;
import software.amazon.kinesis.processor.ShardRecordProcessor;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
import software.amazon.kinesis.retrieval.KinesisClientRecord;
import software.amazon.kinesis.retrieval.polling.PollingConfig;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.CLOUDWATCH;
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.DYNAMODB;
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.KINESIS;
import static software.amazon.kinesis.common.InitialPositionInStream.TRIM_HORIZON;
import static software.amazon.kinesis.common.StreamIdentifier.singleStreamInstance;
#Testcontainers
public class KinesisMultiStreamTest {
static class TestProcessorFactory implements ShardRecordProcessorFactory {
private final TestKinesisRecordService service;
public TestProcessorFactory(TestKinesisRecordService service) {
this.service = service;
}
#Override
public ShardRecordProcessor shardRecordProcessor() {
throw new UnsupportedOperationException("must have streamIdentifier");
}
public ShardRecordProcessor shardRecordProcessor(StreamIdentifier streamIdentifier) {
return new TestRecordProcessor(service, streamIdentifier);
}
}
static class TestRecordProcessor implements ShardRecordProcessor {
public final TestKinesisRecordService service;
public final StreamIdentifier streamIdentifier;
public TestRecordProcessor(TestKinesisRecordService service, StreamIdentifier streamIdentifier) {
this.service = service;
this.streamIdentifier = streamIdentifier;
}
#Override
public void initialize(InitializationInput initializationInput) {
}
#Override
public void processRecords(ProcessRecordsInput processRecordsInput) {
service.addRecord(streamIdentifier, processRecordsInput);
}
#Override
public void leaseLost(LeaseLostInput leaseLostInput) {
}
#Override
public void shardEnded(ShardEndedInput shardEndedInput) {
try {
shardEndedInput.checkpointer().checkpoint();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
#Override
public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
}
}
static class TestKinesisRecordService {
private List<ProcessRecordsInput> firstStreamRecords = Collections.synchronizedList(new ArrayList<>());
private List<ProcessRecordsInput> secondStreamRecords = Collections.synchronizedList(new ArrayList<>());
public void addRecord(StreamIdentifier streamIdentifier, ProcessRecordsInput processRecordsInput) {
if(streamIdentifier.streamName().contains(firstStreamName)) {
firstStreamRecords.add(processRecordsInput);
} else if(streamIdentifier.streamName().contains(secondStreamName)) {
secondStreamRecords.add(processRecordsInput);
} else {
throw new IllegalStateException("no list for stream " + streamIdentifier);
}
}
public List<ProcessRecordsInput> getFirstStreamRecords() {
return Collections.unmodifiableList(firstStreamRecords);
}
public List<ProcessRecordsInput> getSecondStreamRecords() {
return Collections.unmodifiableList(secondStreamRecords);
}
}
public static final String firstStreamName = "first-stream-name";
public static final String secondStreamName = "second-stream-name";
public static final String partitionKey = "partition-key";
DockerImageName localstackImage = DockerImageName.parse("localstack/localstack:latest");
#Container
public LocalStackContainer localstack = new LocalStackContainer(localstackImage)
.withServices(KINESIS, CLOUDWATCH)
.withEnv("KINESIS_INITIALIZE_STREAMS", firstStreamName + ":1," + secondStreamName + ":1");
public Scheduler scheduler;
public TestKinesisRecordService service = new TestKinesisRecordService();
public KinesisProducer producer;
#BeforeEach
void setup() {
KinesisAsyncClient kinesisClient = KinesisClientUtil.createKinesisAsyncClient(
KinesisAsyncClient.builder().endpointOverride(localstack.getEndpointOverride(KINESIS)).region(Region.of(localstack.getRegion()))
);
DynamoDbAsyncClient dynamoClient = DynamoDbAsyncClient.builder().region(Region.of(localstack.getRegion())).endpointOverride(localstack.getEndpointOverride(DYNAMODB)).build();
CloudWatchAsyncClient cloudWatchClient = CloudWatchAsyncClient.builder().region(Region.of(localstack.getRegion())).endpointOverride(localstack.getEndpointOverride(CLOUDWATCH)).build();
MultiStreamTracker tracker = new MultiStreamTracker() {
private List<StreamConfig> configs = List.of(
new StreamConfig(singleStreamInstance(firstStreamName), InitialPositionInStreamExtended.newInitialPosition(TRIM_HORIZON)),
new StreamConfig(singleStreamInstance(secondStreamName), InitialPositionInStreamExtended.newInitialPosition(TRIM_HORIZON)));
#Override
public List<StreamConfig> streamConfigList() {
return configs;
}
#Override
public FormerStreamsLeasesDeletionStrategy formerStreamsLeasesDeletionStrategy() {
return new NoLeaseDeletionStrategy();
}
};
ConfigsBuilder configsBuilder = new ConfigsBuilder(tracker, "KinesisPratTest", kinesisClient, dynamoClient, cloudWatchClient, UUID.randomUUID().toString(), new TestProcessorFactory(service));
scheduler = new Scheduler(
configsBuilder.checkpointConfig(),
configsBuilder.coordinatorConfig(),
configsBuilder.leaseManagementConfig(),
configsBuilder.lifecycleConfig(),
configsBuilder.metricsConfig(),
configsBuilder.processorConfig().callProcessRecordsEvenForEmptyRecordList(false),
configsBuilder.retrievalConfig()
);
new Thread(scheduler).start();
producer = producer();
}
#AfterEach
public void teardown() throws ExecutionException, InterruptedException, TimeoutException {
producer.destroy();
Future<Boolean> gracefulShutdownFuture = scheduler.startGracefulShutdown();
gracefulShutdownFuture.get(60, TimeUnit.SECONDS);
}
public KinesisProducer producer() {
var configuration = new KinesisProducerConfiguration()
.setVerifyCertificate(false)
.setCredentialsProvider(localstack.getDefaultCredentialsProvider())
.setMetricsCredentialsProvider(localstack.getDefaultCredentialsProvider())
.setRegion(localstack.getRegion())
.setCloudwatchEndpoint(localstack.getEndpointOverride(CLOUDWATCH).getHost())
.setCloudwatchPort(localstack.getEndpointOverride(CLOUDWATCH).getPort())
.setKinesisEndpoint(localstack.getEndpointOverride(KINESIS).getHost())
.setKinesisPort(localstack.getEndpointOverride(KINESIS).getPort());
return new KinesisProducer(configuration);
}
#Test
void testFirstStream() {
String expected = "Hello";
producer.addUserRecord(firstStreamName, partitionKey, ByteBuffer.wrap(expected.getBytes(StandardCharsets.UTF_8)));
var result = await().timeout(600, TimeUnit.SECONDS)
.until(() -> service.getFirstStreamRecords().stream()
.flatMap(r -> r.records().stream())
.map(KinesisClientRecord::data)
.map(r -> StandardCharsets.UTF_8.decode(r).toString())
.collect(toList()), records -> records.size() > 0);
assertThat(result).anyMatch(r -> r.equals(expected));
}
#Test
void testSecondStream() {
String expected = "Hello";
producer.addUserRecord(secondStreamName, partitionKey, ByteBuffer.wrap(expected.getBytes(StandardCharsets.UTF_8)));
var result = await().timeout(600, TimeUnit.SECONDS)
.until(() -> service.getSecondStreamRecords().stream()
.flatMap(r -> r.records().stream())
.map(KinesisClientRecord::data)
.map(r -> StandardCharsets.UTF_8.decode(r).toString())
.collect(toList()), records -> records.size() > 0);
assertThat(result).anyMatch(r -> r.equals(expected));
}
}
Here is the error I am getting.
[Thread-9] ERROR software.amazon.kinesis.coordinator.Scheduler - Worker.run caught exception, sleeping for 1000 milli seconds!
java.lang.IllegalArgumentException: Unable to deserialize StreamIdentifier from first-stream-name
at software.amazon.kinesis.common.StreamIdentifier.multiStreamInstance(StreamIdentifier.java:75)
at software.amazon.kinesis.coordinator.Scheduler.getStreamIdentifier(Scheduler.java:1001)
at software.amazon.kinesis.coordinator.Scheduler.buildConsumer(Scheduler.java:917)
at software.amazon.kinesis.coordinator.Scheduler.createOrGetShardConsumer(Scheduler.java:899)
at software.amazon.kinesis.coordinator.Scheduler.runProcessLoop(Scheduler.java:419)
at software.amazon.kinesis.coordinator.Scheduler.run(Scheduler.java:330)
at java.base/java.lang.Thread.run(Thread.java:829)
According to documentation:
The serialized stream identifier should be of the following format: account-id:StreamName:streamCreationTimestamp
So your code should be like this:
private List<StreamConfig> configs = List.of(
new StreamConfig(multiStreamInstance("111111111:multiStreamTest-1:12345"), InitialPositionInStreamExtended.newInitialPosition(TRIM_HORIZON)),
new StreamConfig(multiStreamInstance("111111111:multiStreamTest-2:12389"), InitialPositionInStreamExtended.newInitialPosition(TRIM_HORIZON)));
Note: this also will change leaseKey format to account-id:StreamName:streamCreationTimestamp:ShardId
I am trying to assert output of the below transformed response from sling servlet filter. I am not able to get hold of output response and not able to assert.
import com.day.cq.wcm.api.Page;
import com.safeway.app.rxwa.pharmacy.utils.HttpServletResponseCopier;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.engine.EngineConstants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* This filter rewrites link for the Content Fragment list model exporter
*/
#Component(service = Filter.class,
immediate = true,
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = {
EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
EngineConstants.SLING_FILTER_METHODS + "=GET",
EngineConstants.SLING_FILTER_PATTERN + "=/content/experience-fragments/rxwa/.*",
EngineConstants.SLING_FILTER_SELECTORS + "=model",
EngineConstants.SLING_FILTER_EXTENSIONS + "=json"})
#Designate(ocd = ContentJsonLinkRewriterFilter.Config.class)
public class ContentJsonLinkRewriterFilter implements Filter {
private static final Logger logger =
LoggerFactory.getLogger(ContentJsonLinkRewriterFilter.class);
private Config config;
private List<String> resourceTypes;
#Reference
private ResourceResolverFactory resolverFactory;
#Activate
public void activate(Config config) {
this.config = config;
this.resourceTypes = Arrays.asList(config.resourceTypes());
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// no-op
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
String resultString = "{}";
// add author check
if (!(response instanceof SlingHttpServletResponse) || !(request instanceof SlingHttpServletRequest)) {
throw new IllegalStateException("Filter not properly registered as Sling Servlet Filter");
}
if (!config.enabled()) {
logger.debug("Filter disabled");
filterChain.doFilter(request, response);
return;
}
SlingHttpServletRequest slingHttpServletRequest = (SlingHttpServletRequest) request;
Resource currentResource = slingHttpServletRequest.getResource();
String currentResourceType = currentResource.getResourceType();
if(currentResource.isResourceType("cq:Page")) {
Page page = slingHttpServletRequest.getResource().adaptTo(Page.class);
currentResourceType = page.getContentResource().getResourceType();
}
String finalProcessResourceType = currentResourceType;
if (resourceTypes.stream().noneMatch(resourceType -> StringUtils.startsWith(finalProcessResourceType, resourceType))) {
logger.debug("Current resource path {} is not configured to be evaluated", currentResourceType);
filterChain.doFilter(request, response);
return;
}
// Wrap Response Class before servlet gets called
HttpServletResponseCopier responseCopier = new HttpServletResponseCopier((SlingHttpServletResponse) response);
filterChain.doFilter(request, responseCopier);
// externalize links after the servlet finishes
responseCopier.flushBuffer();
//read original response
byte[] responseBytes = responseCopier.getCopy();
String responseString = new String(responseBytes, responseCopier.getCharacterEncoding());
if (StringUtils.isNotEmpty(responseString)) {
//replace all links
resultString = responseString.replaceAll(StringUtils.substring(slingHttpServletRequest.getRequestURI(),0, slingHttpServletRequest.getRequestURI().lastIndexOf("/")), "");
}
responseCopier.resetBuffer();
responseCopier.getOutputStream().write(resultString.getBytes());
responseCopier.setContentType("application/json");
responseCopier.setCharacterEncoding("utf-8");
}
#Override
public void destroy() {
// no-op
}
#ObjectClassDefinition(name = "Content Fragment List Link Rewriter Filter",
description = "Configuration for filter to extend Content Fragment List functionality to rewrite links")
public #interface Config {
#AttributeDefinition(name = "Enabled",
description = "If this filter should not be active, rather try to delete this config. " + "Only in cases " +
"where this cannot be easily accomplished uncheck this option to disable the filter.") boolean enabled() default false;
#AttributeDefinition(name = "Resource Types",
description = "Resource Types to be evaluated by the filter.") String[] resourceTypes();
}
}
Unit test I tried
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import com.safeway.app.rxwa.pharmacy.utils.HttpServletResponseCopier;
import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.commons.io.IOUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.testing.mock.osgi.MapUtil;
import org.apache.sling.testing.mock.sling.loader.ContentLoader;
import org.apache.sling.testing.mock.sling.servlet.MockSlingHttpServletRequest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.wcm.api.components.ComponentContext;
import com.day.cq.wcm.api.designer.Design;
import com.day.cq.wcm.api.designer.Designer;
import com.google.common.collect.Sets;
import org.mockito.junit.MockitoJUnitRunner;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
#RunWith(MockitoJUnitRunner.class)
public class ContentJsonLinkRewriterFilterTest {
protected static final String CONTENT_ROOT = "/content/experience-fragments/rxwa";
public Map<String, Object> props = new HashMap<>();
#Rule
public AemContext context = new AemContext();
#Mock
FilterChain chain;
public ContentJsonLinkRewriterFilter filter;
#Before
public void setUp() {
context.load().json("/test-page-content.json", "/content/experience-
fragments/rxwa");
props.clear();
props.put("enabled", "true");
props.put("resourceTypes", new String[] {"rxwa-
pharmacy/components/structure/xfpage"});
ContentJsonLinkRewriterFilter aei = context.registerInjectActivateService(new
ContentJsonLinkRewriterFilter(), props);
filter = Mockito.spy(aei);
}
#Test
public void doFilterCall() throws ServletException, IOException {
context.requestPathInfo().setResourcePath("/content/experience-fragments/rxwa/templated-
page");
context.requestPathInfo().setSelectorString("model");
context.requestPathInfo().setExtension("json");
context.request().setMethod("GET");
context.response().setCharacterEncoding("UTF-8");
context.currentPage("/content/experience-fragments/rxwa/templated-page");
Mockito.doAnswer(invocation -> {
HttpServletResponseWrapper httpServletResponseWrapper =
(HttpServletResponseWrapper) invocation.getArguments()[1];
String testHtmlContent = IOUtils.toString(
ContentLoader.class.getResourceAsStream("/test-page-content.json"),
StandardCharsets.UTF_8
);
httpServletResponseWrapper.getWriter()
.write(testHtmlContent);
httpServletResponseWrapper.getWriter().flush();
return null;
}).when(chain).doFilter(Mockito.any(), Mockito.any());
filter.doFilter(context.request(), context.response(), chain);
Mockito.verify(chain).doFilter(Mockito.any(), Mockito.any());
String testHtmlContent2 = IOUtils.toString(
ContentLoader.class.getResourceAsStream("/test-page-content.json"),
StandardCharsets.UTF_8
);
}
}
I've tried many tutorials and looked for documentation, but yet haven't succeeded.
I'll show you my code files directory and an image of the problem.
testmod/TestMod.java :
package com.SkySibe.testmod;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
// The value here should match an entry in the META-INF/mods.toml file
#Mod("testmod")
public class TestMod
{
// Directly reference a log4j logger.
private static final Logger LOGGER = LogManager.getLogger();
public static final String MOD_ID = "testmod";
public static TestMod instance;
public TestMod() {
// Register the setup method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
// Register the doClientStuff method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
instance = this;
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void setup(final FMLCommonSetupEvent event)
{
}
private void doClientStuff(final FMLClientSetupEvent event) {
}
}
testmod/init/BlockInit.java :
package com.SkySibe.testmod.init;
import com.SkySibe.testmod.TestMod;
import net.minecraft.block.Block;
import net.minecraft.block.OreBlock;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraftforge.common.ToolType;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import net.minecraftforge.registries.ObjectHolder;
#ObjectHolder(TestMod.MOD_ID)
#Mod.EventBusSubscriber(modid = TestMod.MOD_ID, bus = Bus.MOD)
public class BlockInit {
public static final Block ruby_ore = null;
#SubscribeEvent
public static void registerBlocks(final RegistryEvent.Register<Block> event) {
event.getRegistry().register(new OreBlock(Block.Properties.create(Material.ROCK).hardnessAndResistance(3.0F, 3.0F).sound(SoundType.STONE).harvestTool(ToolType.PICKAXE)).setRegistryName("ruby_ore"));
}
#SubscribeEvent
public static void registerBlockItems(final RegistryEvent.Register<Item> event) {
event.getRegistry().register(new BlockItem(ruby_ore,new Item.Properties().group(ItemGroup.BUILDING_BLOCKS)).setRegistryName("ruby_ore"));
}
}
assets/testmod/blockstates/ruby_ore.json :
{
"variants": {
"": { "model": "testmod:block/ruby_ore"}
}
}
assets/testmod/models/block/ruby_ore.json :
{
"parent": "block/cube_all",
"textures": {
"all": "testmod:blocks/ruby_ore"
}
}
assets/testmod/models/item/ruby_ore.json :
{
"parent": "testmod:block/ruby_block"
}
(From comment)
You don't write the good item item in the file assets/testmod/models/item/ruby_ore.json. It should be:
{
"parent": "testmod:block/ruby_ore"
}
I would like to know if there is a better way (without reflection) to get the java.security.Permissions for a specific URL and Role.
for example:
boolean canAccess = SecurityController.isAllowedToAccessUrl("/pages/confirmOrders.action", Collections.singletonList(new UserPrincipal("Dave")));
would work with the following constraint (web.xml):
<security-constraint>
<web-resource-collection>
<web-resource-name></web-resource-name>
<url-pattern>/pages/confirmOrders.action</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>Dave</role-name>
</auth-constraint>
The code, I wrote bellow works well. What I don't like is that I have to use reflection to invoke getContextPolicy from DelegatingPolicy.getInstance() and invoke getPermissionsForRole from ContextPolicy.
import org.jboss.security.jacc.ContextPolicy;
import org.jboss.security.jacc.DelegatingPolicy;
import javax.security.jacc.PolicyConfigurationFactory;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebResourcePermission;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Permissions;
import java.security.Principal;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SecurityController {
private static final Logger LOG = Logger.getLogger(SecurityController.class.getName());
static boolean isAllowedToAccessUrl(final String url, final List<Principal> principalRoles) {
initializeConfigurationInService();
boolean result = false;
for (Principal principalRole : principalRoles) {
try{
final ContextPolicy contextPolicy = getContextPolicy();
final Permissions permissions = getPermissionsFromContextPolicy(contextPolicy, principalRole.getName());
result |= permissions.implies(new WebResourcePermission(url, new String[] {"GET","POST"}));
}catch (Exception e){
LOG.log(Level.SEVERE, "checkAllowed failed checking if : ", e);
}
}
return result;
}
private static void initializeConfigurationInService() {
try {
final PolicyConfigurationFactory policyConfigurationFactory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
policyConfigurationFactory.getPolicyConfiguration(PolicyContext.getContextID(), false);
} catch (PolicyContextException | ClassNotFoundException e) {
LOG.log(Level.INFO, "initializeConfigurationInService", e);
}
}
private static Permissions getPermissionsFromContextPolicy(ContextPolicy contextPolicy, String loginName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
final Method getPermissionsForRole = contextPolicy.getClass().getDeclaredMethod("getPermissionsForRole", String.class);
getPermissionsForRole.setAccessible(true);
return (Permissions) getPermissionsForRole.invoke(contextPolicy, loginName);
}
private static ContextPolicy getContextPolicy() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
final DelegatingPolicy delegatingPolicy = DelegatingPolicy.getInstance();
final Method getContextPolicy = delegatingPolicy.getClass().getDeclaredMethod("getContextPolicy", String.class);
getContextPolicy.setAccessible(true);
return (ContextPolicy) getContextPolicy.invoke(delegatingPolicy, PolicyContext.getContextID());
}
}
I read programmatically retrieve security constraints from web.xml but found it not very useful.
Any comments, ideas are really welcome. Thanks!
A similar standard method to do the 'isAllowedToAccessUrl` function is available in Java EE 8.
boolean hasAccessToWebResource(String resource, String... methods)
Checks whether the caller has access to the provided "web resource"
using the given methods, as specified by section 13.8 of the Servlet
specification. A caller has access if the web resource is either not
protected (constrained), or when it is protected by a role and the
caller is in that role.
See: SecurityContext#hasAccessToWebResource
Thanks to the comment of Uux I was able to shorten my code and get rid of using reflection. I am now able to verify if a specific role is allowed to access a specific URL in my code.
workable code below:
import javax.security.jacc.WebResourcePermission;
import java.security.CodeSource;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SecurityController {
private static final Logger LOG = Logger.getLogger(SecurityController.class.getName());
static boolean isAllowedToAccessUrl(final String url, final List<Principal> principalRoles) {
try {
final CodeSource codesource = new CodeSource(null, (Certificate[]) null);
final Principal[] principals = principalRoles.toArray(new Principal[0]);
final ProtectionDomain domain = new ProtectionDomain(codesource, null, null, principals);
return Policy.getPolicy().implies(domain, (new WebResourcePermission(url, new String[] {"GET", "POST"})));
} catch (Exception e) {
LOG.log(Level.SEVERE, "checkAllowed failed checking if : ", e);
}
return false;
}
}
hello:
I'm writing code in java for nutch(open source search engine) to remove the movments from arabic words in the indexer.
I don't know what is the error in it.
Tthis is the code:
package com.mycompany.nutch.indexing;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.Text;
import org.apache.log4j.Logger;
import org.apache.nutch.crawl.CrawlDatum;
import org.apache.nutch.crawl.Inlinks;
import org.apache.nutch.indexer.IndexingException;
import org.apache.nutch.indexer.IndexingFilter;
import org.apache.nutch.indexer.NutchDocument;
import org.apache.nutch.parse.getData().parse.getData();
public class InvalidUrlIndexFilter implements IndexingFilter {
private static final Logger LOGGER =
Logger.getLogger(InvalidUrlIndexFilter.class);
private Configuration conf;
public void addIndexBackendOptions(Configuration conf) {
// NOOP
return;
}
public NutchDocument filter(NutchDocument doc, Parse parse, Text url,
CrawlDatum datum, Inlinks inlinks) throws IndexingException {
if (url == null) {
return null;
}
char[] parse.getData() = input.trim().toCharArray();
for(int p=0;p<parse.getData().length;p++)
if(!(parse.getData()[p]=='َ'||parse.getData()[p]=='ً'||parse.getData()[p]=='ُ'||parse.getData()[p]=='ِ'||parse.getData()[p]=='ٍ'||parse.getData()[p]=='ٌ' ||parse.getData()[p]=='ّ'||parse.getData()[p]=='ْ' ||parse.getData()[p]=='"' ))
new String.append(parse.getData()[p]);
return doc;
}
public Configuration getConf() {
return conf;
}
public void setConf(Configuration conf) {
this.conf = conf;
}
}
I think that the error is in using parse.getdata() but I don't know what I should use instead of it?
The line
char[] parse.getData() = input.trim().toCharArray();
will give you a compile error because the left hand side is not a variable. Please replace parse.getData() by a unique variable name (e.g. parsedData) in this line and the following lines.
Second the import of
import org.apache.nutch.parse.getData().parse.getData();
will also fail. Looks a lot like a text replace issue.