I have a Flyweight pattern implementation in java programming without Spring. Please suggest how do I make this as a Spring managed Bean. It has static method calls and Inner class. The purpose is to initially load all the OptionSets from CRM to share the same OptionSets in the application. This prevents expensive calls to CRM. Users are restricted to create any new OptionSets hence Inner class. First need to implement as a Spring bean and then get it to be ApplicationContextAware to reference other beans. I am primarily using Spring XML configuration for bean definition.
public class OptionSetFactory{
private static Map <String, Object>optionSets = new HashMap();
//Inner class to restrict users creating OptionSet
private class OptionSet implements IOptionSet{
private String entityName;
private String attributeName;
private Hashtable<Integer, String> options;
private IOrganizationService service;
private static final String GUID_EMPTY = "00000000-0000-0000-0000-000000000000";
private ApplicationContext context;
OptionSet(String entityName, String attributeName){
this.entityName = entityName;
this.attributeName = attributeName;
//this.options = options;
OrganizationRequest request = new OrganizationRequest();
request.setRequestName("RetrieveAttribute");
Guid guid = new Guid();
guid.setValue(GUID_EMPTY);
ParameterCollection paramCol = new ParameterCollection();
KeyValuePairOfstringanyType kv0 = new KeyValuePairOfstringanyType();
kv0.setKey("MetadataId");
kv0.setValue(guid);
paramCol.getKeyValuePairOfstringanyTypes().add(kv0);
KeyValuePairOfstringanyType kv1 = new KeyValuePairOfstringanyType();
kv1.setKey("EntityLogicalName");
kv1.setValue(entityName);
paramCol.getKeyValuePairOfstringanyTypes().add(kv1);
KeyValuePairOfstringanyType kv2 = new KeyValuePairOfstringanyType();
kv2.setKey("LogicalName");
kv2.setValue(attributeName);
paramCol.getKeyValuePairOfstringanyTypes().add(kv2);
KeyValuePairOfstringanyType kv3 = new KeyValuePairOfstringanyType();
kv3.setKey("RetrieveAsIfPublished");
kv3.setValue(true);
paramCol.getKeyValuePairOfstringanyTypes().add(kv3);
request.setParameters(paramCol);
try {
OrganizationResponse response=service.execute(request);
PicklistAttributeMetadata pickListAttrMetadata = (PicklistAttributeMetadata)response.getResults().getKeyValuePairOfstringanyTypes().get(0).getValue();
OptionSetMetadata optionSetMetadata = pickListAttrMetadata.getOptionSet();
for(OptionMetadata optionMetaData : optionSetMetadata.getOptions().getOptionMetadatas()){
//TODO populate OptionSet from optionsetMetadata
}
} catch (IOrganizationServiceExecuteOrganizationServiceFaultFaultFaultMessage e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public String getEntityName() {
return entityName;
}
#Override
public String getAttributeName() {
return attributeName;
}
#Override
public Hashtable<Integer, String> getOptions() {
return options;
}
}
//static block to load predefined OptionSets in HashMap
static{
OptionSetFactory factory = new OptionSetFactory();
optionSets.put("dsl_type", factory.new OptionSet("dsl_type", "dsl_operationalstructure"));
}
//Static method calls for user to fetch OptionSet based on inputs
public static IOptionSet getOptionSet(String entityName, String attributeName){
return (IOptionSet) optionSets.get(entityName+"."+attributeName);
}
public static IOptionSet getOptionSet(String attributeName){
return (IOptionSet) optionSets.get(attributeName.toLowerCase());
}
}
Related
In the project am using olingo 2.0.12 jar in the java code.
During the create Entity service call ,
Is there a way to check for which entity data insert requested and,
Alter column values / append new column values before data persisted?
Is there a way to add above?
Code snippet given below,
public class A extends ODataJPADefaultProcessor{
#Override
public ODataResponse createEntity(final PostUriInfo uriParserResultView, final InputStream content,
final String requestContentType, final String contentType) throws ODataJPAModelException,
ODataJPARuntimeException, ODataNotFoundException, EdmException, EntityProviderException {
// Need to check the entity name and need to alter/add column values
}
}
Yes one of the possible ways would be to create your own CustomODataJPAProcessor which extends ODataJPADefaultProcessor.
You will have to register this in JPAServiceFactory by overriding the method
#Override
public ODataSingleProcessor createCustomODataProcessor(ODataJPAContext oDataJPAContext) {
return new CustomODataJPAProcessor(this.oDataJPAContext);
}
Now Olingo will use CustomODataJPAProcessor which can implement the following code to check the entities and transform them if needed
Sample code of CustomODataJPAProcessor
public class CustomODataJPAProcessor extends ODataJPADefaultProcessor {
Logger LOG = LoggerFactory.getLogger(this.getClass());
public CustomODataJPAProcessor(ODataJPAContext oDataJPAContext) {
super(oDataJPAContext);
}
#Override
public ODataResponse createEntity(final PostUriInfo uriParserResultView, final InputStream content,
final String requestContentType, final String contentType) throws ODataException {
ODataResponse oDataResponse = null;
oDataJPAContext.setODataContext(getContext());
InputStream forwardedInputStream = content;
try {
if (uriParserResultView.getTargetEntitySet().getName().equals("Students")) {
LOG.info("Students Entity Set Executed");
if (requestContentType.equalsIgnoreCase(ContentType.APPLICATION_JSON.toContentTypeString())) {
#SuppressWarnings("deprecation")
JsonElement elem = new JsonParser().parse(new InputStreamReader(content));
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
Student s = gson.fromJson(elem, Student.class);
// Change some values
s.setStudentID("Test" + s.getStudentID());
forwardedInputStream = new ByteArrayInputStream(gson.toJson(s).getBytes());
}
}
Object createdJpaEntity = jpaProcessor.process(uriParserResultView, forwardedInputStream,
requestContentType);
oDataResponse = responseBuilder.build(uriParserResultView, createdJpaEntity, contentType);
} catch (JsonIOException | JsonSyntaxException e) {
throw new RuntimeException(e);
} finally {
close();
}
return oDataResponse;
}
}
In Summery
Register your custom org.apache.olingo.odata2.service.factory Code Link
Create your own CustomODataJPAProcessor Code Link
Override createCustomODataProcessor in JPAServiceFactory to use the custom processor Code Link
The purpose of this question is to find out if the codes are written with the right approach. Let's do CRUD operations on categories and posts in the blog website project. To keep the question short, I shared just create and update side.
(Technologies used in the project: spring-boot, mongodb)
Let's start to model Category:
#Document("category")
public class Category{
#Id
private String id;
#Indexed(unique = true, background = true)
private String name;
#Indexed(unique = true, background = true)
private String slug;
// getter and setter
Abstract BaseController class and IController Interface is created for fundamental level save, delete and update operations. I shared below controller side:
public interface IController<T>{
#PostMapping("/save")
ResponseEntity<BlogResponse> save(T object);
#GetMapping(value = "/find-all")
ResponseEntity<BlogResponse> findAll();
#GetMapping(value = "/delete-all")
ResponseEntity<BlogResponse> deleteAll();
}
public abstract class BaseController<T extends MongoRepository<S,String>, S> implements IController<S> {
#Autowired
private T repository;
#Autowired
private BlogResponse blogResponse;
#PostMapping(value = "/save", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public #ResponseBody ResponseEntity<BlogResponse> save(S object) {
try {
S model = (S) repository.save(object);
String modelName = object.getClass().getSimpleName().toLowerCase();
blogResponse.setMessage(modelName + " is saved successfully").putData(modelName, object);
} catch (DuplicateKeyException dke) {
return new ResponseEntity<BlogResponse>(blogResponse.setMessage("This data is already existing!!!"), HttpStatus.BAD_REQUEST);
} catch (Exception e) {
return new ResponseEntity<BlogResponse>(blogResponse.setMessage(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<BlogResponse>(blogResponse, HttpStatus.OK);
}
// delete, findAll and other controllers
#RestController
#RequestMapping(value = "category")
#RequestScope
public class CategoryController extends BaseController<ICategoryRepository, Category>{
// More specific opretions like findSlug() can be write here.
}
And finally BlogResponce component is shared below;
#Component
#Scope("prototype")
public class BlogResponse{
private String message;
private Map<String, Object> data;
public String getMessage() {
return message;
}
public BlogResponse setMessage(String message) {
this.message = message;
return this;
}
public BlogResponse putData(String key, Object object){
if(data == null)
data = new HashMap<String,Object>();
data.put(key,object);
return this;
}
public Map<String,Object> getData(){
return data;
}
#Override
public String toString() {
return "BlogResponse{" +
"message='" + message + '\'' +
", data=" + data +
'}';
}
}
Question: I am new spring boot and I want to move forward by doing it right. BlogResponse is set bean by using #Component annotation. This doc said that other annotations like #Controller, #Service are specializations of #Component for more specific use cases. So I think, I cant use them. BlogResponse is set prototype scope for create new object at each injection. Also it's life end after response because of #RequestScope. Are this annotations using correcty? Maybe there is more effective way or approach. You can remark about other roughness if it existing.
Given siutation like this, author click publish (activate) a page
Then I have following listener to handleEvent
public class ArticleContentActivationEventHandler implements EventHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ArticleContentActivationEventHandler.class);
private static final String ARTICLE_PAGE_TEMPLATE = "/conf/myproject/settings/wcm/templates/article-template";
#Reference
private ResourceResolverService resourceResolverService;
#Override
public void handleEvent(Event event) {
ResourceResolver resourceResolver = null;
try {
resourceResolver = resourceResolverService.getServiceResourceResolver();
String resourcePath = getResourcePath(event);
Resource resource = resourceResolver.getResource(resourcePath);
//the resource is null, the resource path is /content/myproject/us/en,
//resourceResolver is not able to resolve it somehow
for (Iterator<Resource> it = resourceResolver.getResource("/content/myproject/us/en").getChildren().iterator(); it.hasNext(); ) {
Resource r = it.next();
String s = r.getPath();
String t = r.getResourceType();
}
if (resource.isResourceType("cq:Page")) {
Resource jcr_content = resource.getChild("jcr:content");
ValueMap vm = jcr_content.getValueMap();
String template = null;
if (vm.containsKey("cq:template")) {
template = PropertiesUtil.toString(vm.get("cq:template"), "");
}
and below is the interface:
public interface ResourceResolverService {
ResourceResolver getServiceResourceResolver() throws LoginException;
void closeResourceResolver(ResourceResolver resourceResolver);
}
and the impl class:
#Component(service = ResourceResolverService.class, immediate = true)
public class ResourceResolverServiceImpl implements ResourceResolverService {
#Reference
private ResourceResolverFactory resourceResolverFactory;
Logger logger = LoggerFactory.getLogger(ResourceResolverServiceImpl.class);
#Activate
protected void activate() {
logger.info("*** Activating Service ResourceResolverServiceImpl");
}
#Override
public ResourceResolver getServiceResourceResolver() throws LoginException {
final Map<String, Object> param = Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, (Object) "getResourceResolver");
//the ResourceResolver returned here may got some issue?
return resourceResolverFactory.getServiceResourceResolver(param);
}
#Override
public void closeResourceResolver(ResourceResolver resourceResolver) {
resourceResolver.close();
}
}
I do have the osgi config setup by following tutorial http://www.aemcq5tutorials.com/tutorials/resourceresolver-from-resourceresolverfactory/
But in my actually even handler class, it never successfully resolved resource resourceResolver is not able to resolve /content/myproject/us/en , resourceResolver keep give me null value
Could anyone experienced this suggest me some code sample to resolve my issue? thanks
Check the User mapping configuration, the bundle id used in the configuration should match to your project core artifact id.
For example: in the configuration
bundleId = com.day.cq.wcm.cq-msm-core
Alternatively you can try below code instead
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "service-user");
ResourceResolver resolver = resourceResolverFactory.getServiceResourceResolver(param);
I am trying out to write data to my local Elasticsearch Docker Container (7.4.2), for simplicity I used the AbstractReactiveElasticsearchConfiguration given from Spring also Overriding the entityMapper function. The I constructed my repository extending the ReactiveElasticsearchRepository
Then in the end I used my autowired repository to saveAll() my collection of elements containing the data. However Elasticsearch doesn't write any data. Also i have a REST controller which is starting my whole process returning nothing basicly, DeferredResult>
The REST method coming from my ApiDelegateImpl
#Override
public DeferredResult<ResponseEntity<Void>> openUsageExporterStartPost() {
final DeferredResult<ResponseEntity<Void>> deferredResult = new DeferredResult<>();
ForkJoinPool.commonPool().execute(() -> {
try {
openUsageExporterAdapter.startExport();
deferredResult.setResult(ResponseEntity.accepted().build());
} catch (Exception e) {
deferredResult.setErrorResult(e);
}
}
);
return deferredResult;
}
My Elasticsearch Configuration
#Configuration
public class ElasticSearchConfig extends AbstractReactiveElasticsearchConfiguration {
#Value("${spring.data.elasticsearch.client.reactive.endpoints}")
private String elasticSearchEndpoint;
#Bean
#Override
public EntityMapper entityMapper() {
final ElasticsearchEntityMapper entityMapper = new ElasticsearchEntityMapper(elasticsearchMappingContext(), new DefaultConversionService());
entityMapper.setConversions(elasticsearchCustomConversions());
return entityMapper;
}
#Override
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(elasticSearchEndpoint)
.build();
return ReactiveRestClients.create(clientConfiguration);
}
}
My Repository
public interface OpenUsageRepository extends ReactiveElasticsearchRepository<OpenUsage, Long> {
}
My DTO
#Data
#Document(indexName = "open_usages", type = "open_usages")
#TypeAlias("OpenUsage")
public class OpenUsage {
#Field(name = "id")
#Id
private Long id;
......
}
My Adapter Implementation
#Autowired
private final OpenUsageRepository openUsageRepository;
...transform entity into OpenUsage...
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
And finally my IT test
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#Testcontainers
#TestPropertySource(locations = {"classpath:application-it.properties"})
#ContextConfiguration(initializers = OpenUsageExporterApplicationIT.Initializer.class)
class OpenUsageExporterApplicationIT {
#LocalServerPort
private int port;
private final static String STARTCALL = "http://localhost:%s/open-usage-exporter/start/";
#Container
private static ElasticsearchContainer container = new ElasticsearchContainer("docker.elastic.co/elasticsearch/elasticsearch:6.8.4").withExposedPorts(9200);
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(final ConfigurableApplicationContext configurableApplicationContext) {
final List<String> pairs = new ArrayList<>();
pairs.add("spring.data.elasticsearch.client.reactive.endpoints=" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
pairs.add("spring.elasticsearch.rest.uris=http://" + container.getContainerIpAddress() + ":" + container.getFirstMappedPort());
TestPropertyValues.of(pairs).applyTo(configurableApplicationContext);
}
}
#Test
void testExportToES() throws IOException, InterruptedException {
final List<OpenUsageEntity> openUsageEntities = dbPreparator.insertTestData();
assertTrue(openUsageEntities.size() > 0);
final String result = executeRestCall(STARTCALL);
// Awaitility here tells me nothing is in ElasticSearch :(
}
private String executeRestCall(final String urlTemplate) throws IOException {
final String url = String.format(urlTemplate, port);
final HttpUriRequest request = new HttpPost(url);
final HttpResponse response = HttpClientBuilder.create().build().execute(request);
// Get the result.
return EntityUtils.toString(response.getEntity());
}
}
public void doSomething(final List<OpenUsage> openUsages){
openUsageRepository.saveAll(openUsages)
}
This lacks a semicolon at the end, so it should not compile.
But I assume this is just a typo, and there is a semicolon in reality.
Anyway, saveAll() returns a Flux. This Flux is just a recipe for saving your data, and it is not 'executed' until subscribe() is called by someone (or something like blockLast()). You just throw that Flux away, so the saving never gets executed.
How to fix this? One option is to add .blockLast() call:
openUsageRepository.saveAll(openUsages).blockLast();
But this will save the data in a blocking way effectively defeating the reactivity.
Another option is, if the code you are calling saveAll() from supports reactivity is just to return the Flux returned by saveAll(), but, as your doSomething() has void return type, this is doubtful.
It is not seen how your startExport() connects to doSomething() anyway. But it looks like your 'calling code' does not use any notion of reactivity, so a real solution would be to either rewrite the calling code to use reactivity (obtain a Publisher and subscribe() on it, then wait till the data arrives), or revert to using blocking API (ElasticsearchRepository instead of ReactiveElasticsearchRepository).
I'm trying to test if #Async annotation of Spring is working as expected on my project. But It doesn't.
I have this test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = GlobalConfiguration.class)
public class ActivityMessageListenerTest {
#Autowired
private ActivityMessageListener activityMessageListener;
private Long USER_ID = 1l;
private Long COMPANY_ID = 2l;
private Date DATE = new Date(10000000);
private String CLASSNAME = "className";
private Long CLASSPK = 14l;
private Integer TYPE = 22;
private String EXTRA_DATA = "extra";
private Long RECIVED_USER_ID = 99l;
#Before
public void setup() throws Exception {
}
#Test
public void testDoReceiveWithException() throws Exception {
System.out.println("Current thread " + Thread.currentThread().getName());
Map<String, Object> values = new HashMap();
values.put(ActivityMessageListener.PARAM_USER_ID, USER_ID);
values.put(ActivityMessageListener.PARAM_COMPANY_ID, COMPANY_ID);
values.put(ActivityMessageListener.PARAM_CREATE_DATE, DATE);
values.put(ActivityMessageListener.PARAM_CLASS_NAME, CLASSNAME);
values.put(ActivityMessageListener.PARAM_CLASS_PK, CLASSPK);
values.put(ActivityMessageListener.PARAM_TYPE, TYPE);
values.put(ActivityMessageListener.PARAM_EXTRA_DATA, EXTRA_DATA );
values.put(ActivityMessageListener.PARAM_RECEIVED_USER_ID, RECIVED_USER_ID);
Message message = new Message();
message.setValues(values);
MessageBusUtil.sendMessage(MKTDestinationNames.ACTIVITY_REGISTRY, message);
}
}
As you can see I'm printing the name of the current thread.
The class containing the #Async method is:
public class ActivityMessageListener extends BaseMessageListener {
public static final String PARAM_USER_ID = "userId";
public static final String PARAM_COMPANY_ID = "companyId";
public static final String PARAM_CREATE_DATE = "createDate";
public static final String PARAM_CLASS_NAME = "className";
public static final String PARAM_CLASS_PK = "classPK";
public static final String PARAM_TYPE = "type";
public static final String PARAM_EXTRA_DATA = "extraData";
public static final String PARAM_RECEIVED_USER_ID = "receiverUserId";
public ActivityMessageListener() {
MessageBusUtil.addQueue(MKTDestinationNames.ACTIVITY_REGISTRY, this);
}
#Override
#Async(value = "activityExecutor")
public void doReceive(Message message) throws Exception {
System.out.println("Current " + Thread.currentThread().getName());
if (1> 0)
throw new RuntimeException("lalal");
Map<String, Object> parameters = message.getValues();
Long userId = (Long)parameters.get(ActivityMessageListener.PARAM_USER_ID);
Long companyId = (Long)parameters.get(ActivityMessageListener.PARAM_COMPANY_ID);
Date createDate = (Date)parameters.get(ActivityMessageListener.PARAM_CREATE_DATE);
String className = (String)parameters.get(ActivityMessageListener.PARAM_CLASS_NAME);
Long classPK = (Long)parameters.get(ActivityMessageListener.PARAM_CLASS_PK);
Integer type = (Integer)parameters.get(ActivityMessageListener.PARAM_TYPE);
String extraData = (String)parameters.get(ActivityMessageListener.PARAM_EXTRA_DATA);
Long receiverUserId = (Long)parameters.get(ActivityMessageListener.PARAM_RECEIVED_USER_ID);
ActivityLocalServiceUtil.addActivity(userId, companyId, createDate, className, classPK, type, extraData, receiverUserId);
}
}
Here I'm printing the name of the current thread inside of the #Async method, and the name is the same as before, main. So it's not working.
The GlobalConfiguration is:
#Configuration
#EnableAspectJAutoProxy
#EnableTransactionManagement
#ComponentScan({
"com.shn.configurations",
...some packages...
})
public class GlobalConfiguration {...}
And inside one of the specified packages has the activityExecutor bean:
#Configuration
#EnableAsync(proxyTargetClass = true)
public class ExecutorConfiguration {
#Bean
public ActivityMessageListener activityMessageListener() {
return new ActivityMessageListener();
}
#Bean
public TaskExecutor activityExecutor()
{
ThreadPoolTaskExecutor threadPoolTaskExecutor =
new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(100);
return threadPoolTaskExecutor;
}
}
What I'm doing wrong?
Tricky.
Asynchronous behavior is added through proxying.
Spring provides you with a proxy that wraps the actual object and performs the actual invocation in a separate thread.
It looks something like this (except most of this is done dynamically with CGLIB or JDK proxies and Spring handlers)
class ProxyListener extends ActivityMessageListener {
private ActivityMessageListener real;
public ProxyListener(ActivityMessageListener real) {
this.real = real;
}
TaskExecutor executor; // injected
#Override
public void doReceive(Message message) throws Exception {
executor.submit(() -> real.doReceive(message)); // in another thread
}
}
ActivityMessageListener real = new ActivityMessageListener();
ProxyListener proxy = new ProxyListener(real);
Now, in a Spring world, you'd have a reference to the proxy object, not to the ActivityMessageListener. That is
ActivityMessageListener proxy = applicationContext.getBean(ActivityMessageListener.class);
would return a reference to the ProxyListener. Then, through polymorphism, invoking doReceive would go to the overriden Proxy#doReceive method which would invoke ActivityMessageListener#doReceive through delegation and you'd get your asynchronous behavior.
However, you're in a half Spring world.
Here
public ActivityMessageListener() {
MessageBusUtil.addQueue(MKTDestinationNames.ACTIVITY_REGISTRY, this);
}
the reference this is actually referring to the real ActivityMessageListener, not to the proxy. So when, presumably, you send your message on the bus here
MessageBusUtil.sendMessage(MKTDestinationNames.ACTIVITY_REGISTRY, message);
you're sending it to the real object, which doesn't have the proxy asynchronous behavior.
The full Spring solution would be to have the MessabeBus (and/or its queue) be Spring beans in which you can inject the fully process (proxied, autowired, initialized) beans.
In reality, since CGLIB proxies are really just subclasses of your types, so the ProxyListener above would actually also add itself to the bus since the super constructor would be invoked. It would seem though that only one MessageListener can register itself with a key, like MKTDestinationNames.ACTIVITY_REGISTRY. If this isn't the case, you'd have to show more of that code for explanation.
In your test, if you do
activityMessageListener.doReceive(message);
you should see that asynchronous behavior since activityMessageListener should hold a reference to the proxy.