AEM : getSlingScriptHelper().getService returns null - aem

I am trying to use the getSlingScriptHelper().getService in my project but it keeps returning null. I have done this in other projects and the implementation is similar. We are using sightly on AEM 6.3 in the project. My code below:
FOOModel :
public class FOOModel extends WCMUsePojo {
private static final Logger LOGGER = LoggerFactory.getLogger(FOOModel.class);
private String foo;
#Override
public void activate() throws Exception{
FOOInterface fooInterface = getSlingScriptHelper().getService(FOOInterface.class);
LOGGER.info("FOOInterface value is : " + fooInterface);
}
public String getFoo() {
return foo;
}
}
FooInterface :
public interface FOOInterface {
public String getFoo();
}
FOO Implementation :
#Component(metatype = true, immediate = true, label = "FOO Configuration", description = "OSGi Configuration FOO")
#Service(FOOInterface.class)
public class FOOImpl implements FOOInterface {
#Property(label = "FOO", description = "FOO to be provided")
public static final String FOO_URL = "foo.url";
private String foo;
#Activate
public void activate(ComponentContext componentContext){
Dictionary<?, ?> props = componentContext.getProperties();
this.foo = PropertiesUtil.toString(props.get(FOO_URL), StringUtils.EMPTY);
}
#Override
public String getSsoUrl() {
return foo;
}
}
The logs show "FOOInterface value is : null".
I've tried the sling model with class injection method but it did not work either.
EDIT : I have found that the service is not active. Attaching screenshot for the bundle status.

Most probably your FOOInterface service is not active. You can check /system/console/components to see its status.
The bundle that includes that service might not be properly installed. You can check its status at /system/console/bundles.

Related

Inheriting logging services from base class

I have a .Net Core 3.1 API controller with a constructor that looks like this:
public class MachineListsController : ControllerBase
{
private readonly jiWeb_ProdContext _context;
private readonly ILogger _logger;
private readonly ILoggingMessageService _loggingMessage;
public MachineListsController(jiWeb_ProdContext context, ILogger<MachineListsController> logger, ILoggingMessageService loggingMessage)
{
_context = context;
_logger = logger;
_loggingMessage = loggingMessage;
}
public string Message { get; set; }
...
}
You can see that I am injecting a .Net Core logging service and the database context into it.
Then I use the logging like this in my controller methods:
[HttpGet("FactoryMachines/{factoryId}")]
public async Task<ActionResult<IEnumerable<MachineList>>> GetMachinesForFactory(Guid factoryId)
{
var machineList = await _context.MachineList.Where(n => n.FactoryId == factoryId).ToListAsync();
Message = _loggingMessage.GetLogSuccess(this.GetType().Name.ToString(), ControllerActions.GetAction, "FactoryMachines", factoryId.ToString());
_logger.LogInformation(Message);
return machineList;
}
The logging is working great, but I'm realizing that I should create a base class that handles logging so I don't have to add or change it inside of every controller I write.
So I started to write this base controller:
[ApiController]
public class MyBaseController : ControllerBase
{
readonly jiWeb_ProdContext _context;
readonly ILogger _logger;
readonly ILoggingMessageService _loggingMessage;
public BaseController(jiWeb_ProdContext context, ILogger<BaseController> logger, ILoggingMessageService loggingMessage)
{
_context = context;
_logger = logger;
_loggingMessage = loggingMessage;
}
}
Then I changed my controller to inherit from it like this:
public class MachineListsController : MyBaseController
{
[HttpGet("FactoryMachines/{factoryId}")]
public async Task<ActionResult<IEnumerable<MachineList>>> GetMachinesForFactory(Guid factoryId)
{
var machineList = await _context.MachineList.Where(n => n.FactoryId == factoryId).ToListAsync();
return machineList;
}
}
But I'm getting error and I'm unsure of what to do on the next step.
Here's the error:
There is no argument given that corresponds to the required formal parameter 'context' of 'BaseController.BaseController(jiWeb_ProdContext, ILogger<BaseController>, ILoggingMessageService)'
Specifically, how do I set up my controllers so that they can just use the base class for logging so I don't have to write logging code for every new controller action I create?
Thanks!
As far as I know, if the base class constructor method contains value, we should pass it in the subclass constructor method and also you should follow Nkosi comment to modify the property to protected.
More details, you could refer to below codes:
[ApiController]
public class MyBaseController : ControllerBase
{
protected readonly ILogger _logger;
public MyBaseController(ILogger<MyBaseController> logger)
{
_logger = logger;
}
}
[Route("api/[controller]")]
public class MachineListsController : MyBaseController
{
public MachineListsController(ILogger<MyBaseController> logger) :base(logger)
{
}
[HttpGet]
public IActionResult Get() {
_logger.Log(Microsoft.Extensions.Logging.LogLevel.Trace,"aaa" );
return Ok();
}
}
I am wondering, would there be a way to do the logging in the base class? Like where you call _logger.Log in the MachineListsController class, could that be moved to base?
As far as I know, we could only add logs before the MachineListsController's action executed or after the MachineListsController's action executed.
If this match your requirement, you could try to use action filter.
You could add iactionfilter interface to the basecontroller and overried the OnActionExecuted and OnActionExecuting method.
More details, you could refer to below codes:
[Route("api/[controller]")]
[ApiController]
public class MyBaseController : ControllerBase, IActionFilter
{
protected readonly ILogger _logger;
public MyBaseController(ILogger<MyBaseController> logger)
{
_logger = logger;
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.Log(Microsoft.Extensions.Logging.LogLevel.Trace, "aaa");
int i = 0;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.Log(Microsoft.Extensions.Logging.LogLevel.Trace, "bbb");
int i = 0;
}
}
Result:

GWT result state changes after dispatch

data item boolean flag won't hold its state when item is returned from server through dispatcher to Presenter (client side).
shared package
public class ResourceItem extends BaseResourceItem implements IsSerializable {
private String name;
public ResourceItem() {
super();
}
public ResourceItem(String name) {
super(true);
this.name = name;
}
}
public class BaseResourceItem {
private boolean removeEnabled = true;
public BaseResourceItem() {
super();
}
public BaseResourceItem(boolean removeEnabled) {
super();
this.removeEnabled = removeEnabled;
}
public boolean isRemoveEnabled() {
return removeEnabled;
}
public void setRemoveEnabled(boolean removeEnabled) {
this.removeEnabled = removeEnabled;
}
}
Flag in question is removeEnabled . By default it's true, and even though I set it to false in server side, when Presenter gets it, it's been set to false for some reason. Am I missing something with serialization? (can't think of anything else at this point).
Server package
#GenDispatch
public class GetModelSettings {
#Out(1)
List<ResourceItem> listOfSettings;
}
public class GetModelSettingsHandler implements ActionHandler<GetModelSettingsAction, GetModelSettingsResult> {
#Override
public GetModelSettingsResult execute(GetModelSettingsAction action, ExecutionContext context)
throws ActionException {
ResourceItem item1 = new ResourceItem();
ResourceItem item2 = new ResourceItem();
item2.setRemoveEnabled(false);
list.add(item1);
list.add(item2);
// item1 -> true
// item2 -> false
return new GetModelSettingsResult(list);
}
}
As you can see, a simple handler return a list. At this point, data is correct, one item has flag set to true, the other one to false.
Client package
public class ModelSettingsPresenter {
dispatcher.execute(new GetModelSettingsAction(), new AsyncCallback<GetModelSettingsResult>() {
#Override
public void onSuccess(GetModelSettingsResult result) {
itemList = result.getListOfSettings();
// itemList.get(0) -> true
// itemList.get(1) -> true
}
});
}
Data items both have flags set to true in this presenter. Any ideas why is this happening?
This has to do with serialization used with inheritance.
During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable. The fields of serializable subclasses will be restored from the stream.
More on it can be found in different thread Java object Serialization and inheritance

Why does my sub-dependency not get set in Dagger?

I am having a hard time figuring out how to inject CachedRithms into my RithmioManager and CachedKamms into my KamilManager?
I have the following files:
AppScopeModule:
#Module
(
library = true,
complete = false,
injects = {
KamilApplication.class,
KamilManager.class
}
)
public class AppScopeModule {
/* package */ static Context sApplicationContext = null;
private final Context mApplicationContext;
AppScopeModule(Context applicationContext) {
KamilManager.initInstance(applicationContext);
mApplicationContext = applicationContext;
}
#Provides
#Singleton
KamilManager provideKamilManager() {
return KamilManager.getInstance();
}
}
KamilApplication:
public class KamilApplication extends Application implements Injector {
private ObjectGraph mObjectGraph;
#Inject
KamilManager KamilManager;
#Override
public void onCreate() {
super.onCreate();
AppScopeModule sharedAppModule = new AppScopeModule(this);
// bootstrap. So that it allows no-arg constructor in AppScopeModule
sharedAppModule.sApplicationContext = this.getApplicationContext();
List<Object> modules = new ArrayList<Object>();
modules.add(sharedAppModule);
modules.add(new AuthModule());
modules.addAll(getAppModules());
mObjectGraph = ObjectGraph.create(modules.toArray());
mObjectGraph.inject(this);
}
}
KamilManager
public class KamilManager {
#Inject
CachedKamms mCachedKamms;
private static KamilManager instance;
private boolean mWearIsConnectedToMobile;
private KamilManager() {
Log.d(TAG, "KamilManager private constructor");
}
public static void initInstance(Context appContext) {
if (instance == null) {
instance = new KamilManager();
.....doing more things here...
}
}
public static KamilManager getInstance() {
return instance;
}
}
But mCAchedKamms is always blank when I initialize the app. Any idea what I'm doing wrong?
You need to call ObjectGraph.inject(this) somewhere in KamilManager.
I suggest you to add this code to your KamilApplication class:
public ObjectGraph getObjectGraph() {
return mObjectGraph;
}
After that you need to somehow get instance of KamilApplication(pass it via constructor maybe?) in KamilManager and call:
kamilApplication.getObjectGraph.inject(this);
after this call every field in class KamilManager annotated with #Inject should be injected.
OR
Just annotate constructor of CachedKamms with #Inject
Extra:
Avoid of using library = true and complete = false unless you know what are you doing. With this settings you disable some validations at compile time.

JPA2.0 property access in spring rest data -- some getters not being called

I am still somewhat of a novice with Spring Boot and Spring Data Rest and hope someone out there with experience in Accessing by Property. Since I cannot change a database which stores types for Letters in an unnormalized fashion (delimited string in a varchar), I thought that I could leverage some logic in properties to overcome this. However I notice that when using property access, some of my getters are never called.
My Model code:
package ...
import ...
#Entity
#Table(name="letters", catalog="clovisdb")
#Access(AccessType.PROPERTY)
public class Letter {
public enum PhoneticType {
VOWEL, SHORT, LONG, COMMON;
public static boolean contains(String s) { ... }
}
public enum PositionType {
ALL, INITIAL, MEDIAL, FINAL;
public static boolean contains(String s) { ... }
}
public enum CaseType {
ALL, LOWER, UPPER;
public static boolean contains(String s) { ... }
}
private int id;
private String name;
private String translit;
private String present;
private List<PhoneticType> phoneticTypes;
private CaseType caseType;
private PositionType positionType;
#Id
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getTranslit() { return translit; }
public void setTranslit(String translit) { this.translit = translit; }
public String getPresent() { return present; }
public void setPresent(String present) { this.present = present; }
public String getTypes() {
StringBuilder sb = new StringBuilder(); //
if (phoneticTypes!=null) for (PhoneticType type : phoneticTypes) sb.append(" ").append(type.name());
if (caseType!=null) sb.append(" ").append(caseType.name());
if (positionType!=null) sb.append(" ").append(positionType.name());
return sb.substring( sb.length()>0?1:0 );
}
public void setTypes(String types) {
List<PhoneticType> phoneticTypes = new ArrayList<PhoneticType>();
CaseType caseType = null;
PositionType positionType = null;
for (String val : Arrays.asList(types.split(" "))) {
String canonicalVal = val.toUpperCase();
if (PhoneticType.contains(canonicalVal)) phoneticTypes.add(PhoneticType.valueOf(canonicalVal));
else if (CaseType.contains(canonicalVal)) caseType = CaseType.valueOf(canonicalVal);
else if (PositionType.contains(canonicalVal)) positionType = PositionType.valueOf(canonicalVal);
}
this.phoneticTypes = phoneticTypes;
this.caseType = (caseType==null)? CaseType.ALL : caseType;
this.positionType = (positionType==null)? PositionType.ALL : positionType;
}
#Override
public String toString() { .... }
}
My Repository/DAO code:
package ...
import ...
#RepositoryRestResource
public interface LetterRepository extends CrudRepository<Letter, Integer> {
List<Letter> findByTypesLike(#Param("types") String types);
}
Hitting this URI: http://mytestserver.com:8080/greekLetters/6
and setting breakpoints on all the getters and setters, I can see that the properties are called in this order:
setId
setName
setPresent
setTranslit
setTypes
(getId not called)
getName
getTranslit
getPresent
(getTypes not called !!)
The json returned for the URI above reflects all the getters called, and there are no errors
{
"name" : "alpha",
"translit" : "`A/",
"present" : "Ἄ",
"_links" : {
"self" : {
"href" : "http://mytestserver.com:8080/letters/6"
}
}
}
But why is my getTypes() not being called and my JSON object missing the “types” attribute? I note that the setter is called, which makes it even stranger to me.
Any help would be appreciated!
Thanks in advance
That's probably because you don't have a field types, so getTypes() isn't a proper getter. Try adding this to your entity
#Transient
private String types;
I don't know how the inner works, but it's possible that the class is first scanned for its fields, and then a getter is called for each field. And since you don't have types field, the getter isn't called. Setter getting called could be a feature but I wouldn't be surprised if it is a bug, because findByTypesLike should translate to find Letters whose types field is like <parameter>, and types is not a field.
Another thing you can try, is to annotate that getter with #JsonInclude. Jackson 2 annotations are supported in Spring versions 3.2+ (also backported to 3.1.2).

creating a GWT ValueProxy and sending to a service method

I want to call a method on a Service with a ValueProxy param - if I do personProxy.setName("test") and then request.callFn(personProxy).fire(), the name property doesn't get passed to server.
Should I do a request.edit(personProxy) before setting the name or something else?
This is the implementation I'm using:
//somewhere in MyActivity.java ...
PersonProxy cp = requestFactory.myRequest().create(PersonProxy.class);
cp.setName("John Doe");
requestFactory.myRequest().doSomething(cp,"extra_param_value").fire(new Receiver<List<PersonProxy>>() {
#Override
public void onSuccess(List<PersonProxy> response) {
//response from server...
}
});
//------------------------
public interface MyRequestFactory extends RequestFactory {
MyRequest myRequest();
}
//------------------------
#ServiceName(value="com.server.MyService", locator="com.server.MyServiceLocator")
public interface MyRequest extends RequestContext {
public Request<Integer> doSomething(PersonProxy param, String extraParam);
}
//------------------------
public class MyServiceLocator implements ServiceLocator {
public Object getInstance(Class<?> clazz) {
return new MyService();
}
}
//------------------------
public class MyService {
public Integer doSomething(Person param, String extraParam) {
System.out.println("person.name="+param.getName()); ---> prints NULL!!! why?
return 0;
}
}
//------------------------
#ProxyForName(value="com.server.Person")
public interface PersonProxy extends ValueProxy {
String getName();
void setName(String name);
}
//-----------------------
public class Person {
public Person() {
super();
}
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Thanks.
The PersonProxy is being created by one instance of a RequestContext and used in another. Turns out there's a bug in AbstractRequestContext.retainArg() that should have thrown an exception to tell you about the API mis-use. Editable proxies aren't supposed to be usable between different RequestContext instances.
TreeRequest ctx = factory.treeRequest();
PersonProxy person = ctx.create(PersonProxy.class);
person.setName("John Doe");
ctx.doSomething(person, "more stuff");
As discussed on IRC, the -Dgwt.rpc.dumpPayload=true JVM flag can be turned on when trying to diagnose where data is going (or isn't).