I have created an event handler and used OSGi configuration as below.
#Component(immediate = true,
service=EventHandler.class,
property= {
EventConstants.EVENT_TOPIC + "=" + ReplicationAction.EVENT_TOPIC
}
)
#Designate(ocd = PagePublishEventHandler.Configuration.class)
public class PagePublishEventHandler implements EventHandler {
private static String rootPage = "";
#Override
public void handleEvent(final Event event) {
}
#Activate
#Modified
public void activate(Configuration config) {
String rootPage = config.getPath();
logger.info("********ConfigurationPropertyInterface**********activate**********************");
logger.info("********rootPage********",rootPage);
}
#ObjectClassDefinition(name="AEM Plugin OSGi Configuration")
public #interface Configuration {
#AttributeDefinition(
name = "Root Page For Web Site",
description = "Configurable paths for root page",
type = AttributeType.STRING
)
String getPath() default "/content";
}
}
Inside the activate method, Value of rootPage is always blank. Do anyone has the solution on this.
I
Thanks
I ran your code in my machine and I don't see any issues with it except for the following things which I noticed.
The rootPage is defined as a static variable. Though this is not the cause of the issue in question, it might cause issues during runtime.
You are not printing the value of the rootPage in your log (probably that is why you think that the value is null?). In order to print it, use format specifiers as shown below.
logger.info("********rootPage******** {}",rootPage);
Related
I use Liferay 7.2 and Liferay IDE (eclipse). I created two separate Liferay admin portlet to creating a view for the database entries. I added in the first portlet "Teachers" a new panel called school with this generated code in application.list Package.
here is the code of - PanelApp.java
#Component(
immediate = true,
property = {
"panel.app.order:Integer=300",
"panel.category.key=" + TeachersPanelCategoryKeys.CONTROL_PANEL_CATEGORY
},
service = PanelApp.class
)
public class TeachersPanelApp extends BasePanelApp {
#Override
public String getPortletId() {
return TeachersPortletKeys.TEACHERS;
}
#Override
#Reference(
target = "(javax.portlet.name=" + TeachersPortletKeys.TEACHERS+ ")",
unbind = "-"
)
public void setPortlet(Portlet portlet) {
super.setPortlet(portlet);
}
}
.
public class TeachersPanelCategoryKeys {
public static final String CONTROL_PANEL_CATEGORY = "Teachers";
}
And here is the code of - PanelCategory.java
#Component(
immediate = true,
property = {
"panel.category.key=" + PanelCategoryKeys.SITE_ADMINISTRATION,
"panel.category.order:Integer=300"
},
service = PanelCategory.class)
public class TeachersPanelCategory extends BasePanelCategory {
#Override
public String getKey() {
return TeachersPanelCategoryKeys.CONTROL_PANEL_CATEGORY;
}
#Override
public String getLabel(Locale locale) {
return LanguageUtil.get(locale, "School");
}}
And here is the code of portlet.java
#Component(
immediate = true,
property = {
"com.liferay.portlet.add-default-resource=true",
"com.liferay.portlet.display-category=category.hidden",
"com.liferay.portlet.header-portlet-css=/css/main.css",
"com.liferay.portlet.layout-cacheable=true",
"com.liferay.portlet.private-request-attributes=false",
"com.liferay.portlet.private-session-attributes=false",
"com.liferay.portlet.render-weight=50",
"com.liferay.portlet.use-default-template=true",
"javax.portlet.display-name=Teachers",
"javax.portlet.expiration-cache=0",
"javax.portlet.init-param.template-path=/",
"javax.portlet.init-param.view-template=/view.jsp",
"javax.portlet.name=" + TeachersPortletKeys.TEACHERS,
"javax.portlet.resource-bundle=content.Language",
"javax.portlet.security-role-ref=power-user,user",
},
service = Portlet.class
)
public class TeachersPortlet extends MVCPortlet {
// some code to get entries from db
#Override
public void doView(final RenderRequest renderRequest, final RenderResponse renderResponse)
throws IOException, PortletException {
// some code
Now I want to add the second created portlet "Students" under the same Panel "School". I created it in the same way as "Teachers" but now I have two school panel. As it is shown in the image below.
I just want to display one panel category called school that contain both Teachers and Students in the list.
I do not know how I can think to do that.
As you're implementing a TeachersPanelCategory, I'm assuming you're also implementing a StudentsPanelCategory. From a naming perspective, I'd have expected a SchoolPanelCategory.
I'm currently at a loss of how the ControlPanel portlets actually declare their associated panel, but that place would be where you pick the common "school" panel and use the same spelling for both.
In other words: If you deploy two panels with the same name, I'd expect exactly what you document here. Make sure you're only deploying one of them
Edit: I'd like to know what TeachersPanelCategoryKeys.CONTROL_PANEL_CATEGORY is defined as, and the corresponding (assumed, not shown) StudentsPanelCategoryKeys.CONTROL_PANEL_CATEGORY. Both categories have the same label, but if they have different keys, they'll be different. I'm not sure what happens when you deploy two components with the same key: You should deploy only one.
Edit2: I've missed the code before: You're producing the key to your first category as "Teachers", and the label as "School". I'm assuming that the key for your other category is "Students". Liferay organizes the categories by key - and if the keys are different, then you'll end up with two different categories. Make their key more similar to their name (e.g. create a single SchoolCategory and associate your portlets/panelApps with that:
#Component(
immediate = true,
property = {
"panel.category.key=" + PanelCategoryKeys.SITE_ADMINISTRATION,
"panel.category.order:Integer=300"
},
service = PanelCategory.class)
public class SchoolPanelCategory extends BasePanelCategory {
#Override
public String getKey() {
return "school"; // this is the category that you want to associate with
}
#Override
public String getLabel(Locale locale) {
return LanguageUtil.get(locale, "School");
}
}
and
#Component(
immediate = true,
property = {
"panel.app.order:Integer=300",
"panel.category.key=school" // referencing the category created above
// (use the same for your StudentsPanelApp)
},
service = PanelApp.class
)
public class TeachersPanelApp extends BasePanelApp {
#Override
public String getPortletId() {
return TeachersPortletKeys.TEACHERS;
}
#Override
#Reference(
target = "(javax.portlet.name=" + TeachersPortletKeys.TEACHERS+ ")",
unbind = "-"
)
public void setPortlet(Portlet portlet) {
super.setPortlet(portlet);
}
}
(See the one-line comments within the code for the critical lines. Replace with proper constants if you like)
I am using Activities and Places.
I have a LoginPlace.
The url displayed when I navigate to that place has this at the end:
#LoginPlace:login
How can I change this to just #login or something else?
My tokenizer looks like this:
public class LoginTokenizer implements PlaceTokenizer<LoginPlace> {
private LoginPlace loginPlace;
public LoginTokenizer() {
}
#Override
public LoginPlace getPlace(String token) {
return new LoginPlace(token);
}
#Override
public String getToken(LoginPlace place) {
loginPlace = place;
return loginPlace.getLoginToken();
}
}
And navigation to the LoginPlace is done through the PlaceController:
clientFactory.getPlaceController().goTo(new LoginPlace("login"));
Where can I manipulate the format of the URL?
The mapping is done by the PlaceHistoryMapper.
You can have an implementation generated by GWT based in PlaceTokenizers, but then it's based on a prefix/suffix. The #Prefix allows you configure the prefix (which otherwise defaults to the place class' name).
Or you can implement the interface yourself and have complete control over the process.
Rename the Place class from LoginPlace to Login.
Pass an empty token:
new LoginPlace("")
I want to create my own SonarQube Plugin for the RPG language. I have the following problem.
I start by created the RpgLanguage class that extends to AbstractLanguage. In this class, I defined my new language "Rpg". You can see my class in the following code :
public class RpgLanguage extends AbstractLanguage{
public static final String KEY = "rpg";
private Settings settings;
public RpgLanguage(Settings settings) {
super(KEY, "Rpg");
this.settings = settings;
}
public String[] getFileSuffixes() {
String[] suffixes = settings.getStringArray("");
if (suffixes == null || suffixes.length == 0) {
suffixes = StringUtils.split(".RPG", ",");
}
return suffixes;
}
}
After, I have created my RpgRulesDefinition class that implements RulesDefinition. In this class, I create a new repository for the language RPG and I want to add a rule in this repository (empty rules). The code is like below :
public static final String REPOSITORY_KEY = "rpg_repository_mkoza";
public void define(Context context) {
NewRepository repo = context.createRepository(REPOSITORY_KEY, "rpg");
repo.setName("Mkoza Analyser rules RPG");
// We could use a XML or JSON file to load all rule metadata, but
// we prefer use annotations in order to have all information in a single place
RulesDefinitionAnnotationLoader annotationLoader = new RulesDefinitionAnnotationLoader();
annotationLoader.load(repo, RpgFileCheckRegistrar.checkClasses());
repo.done();
}
My class RpgFileCheckRegistrar that call my Rules :
/**
* Register the classes that will be used to instantiate checks during analysis.
*/
public void register(RegistrarContext registrarContext) {
// Call to registerClassesForRepository to associate the classes with the correct repository key
registrarContext.registerClassesForRepository(RpgRulesDefinition.REPOSITORY_KEY, Arrays.asList(checkClasses()), Arrays.asList(testCheckClasses()));
}
/**
* Lists all the checks provided by the plugin
*/
public static Class<? extends JavaCheck>[] checkClasses() {
return new Class[] {
RulesExampleCheck.class
};
}
/**
* Lists all the test checks provided by the plugin
*/
public static Class<? extends JavaCheck>[] testCheckClasses() {
return new Class[] {};
}
My Rule class (still empty):
#Rule(
key = "Rule1",
name = "Rule that make nothing",
priority = Priority.MAJOR,
tags = {"example"}
)
public class RulesExampleCheck extends BaseTreeVisitor{
/**
* Right in java code your rule
*/
}
And the class SonarPlugin that call all these extensions :
public final class RpgSonarPlugin extends SonarPlugin
{
// This is where you're going to declare all your Sonar extensions
public List getExtensions() {
return Arrays.asList(
RpgLanguage.class,
RpgRulesDefinition.class,
RpgFileCheckRegistrar.class
);
}
}
The problem when I want to start the server sonar, I obtain this error stack :
Exception sending context initialized event to listener instance of class org.sonar.server.platform.PlatformServletContextListener
java.lang.IllegalStateException: One of HTML description or Markdown description must be defined for rule [repository=rpg_repository_mkoza, key=Rule1]
I try different things but I don't understand why there are these error.
Of course I want that my repository "rpg_repository_mkoza" is display in the RPG's repository in SonarQube with the Rules : RulesExampleCheck.
My sonar-plugin-version is the 3.7.1
I find my problem. There are need to add the field 'description' in #Rule.
For example :
#Rule(
key = "Rule1",
name = "RuleExampleCheck",
description = "This rule do nothing",
priority = Priority.INFO,
tags = {"try"}
)
I use junit to assert the existing of wicket components:
wicketTester.assertComponent("dev1WicketId:dev2WicketId:formWicketId", Form.class);
This works for some forms. For complex structure, it is defficult to find out the path of the form by searching all html files. Is there any method how to find out the path easy?
If you have the component you can call #getPageRelativePath(). E.g.
// Supposing c is a component that has been added to the page.
// Returns the full path to the component relative to the page, e.g., "path:to:label"
String pathToComponent = c.getPageRelativePath();
You can get the children of a markup container by using the visitChildren() method. The following example shows how to get all the Forms from a page.
List<Form> list = new ArrayList<Form<?>>();
Page page = wicketTester.getLastRenderedPage();
for (Form form : page.visitChildren(Form.class)) {
list.add(form);
}
An easy way to get those is to call getDebugSettings().setOutputComponentPath(true); when initializing your application. This will make Wicket to output these paths to the generated HTML as an attribute on every component-bound tag.
It's recommended to only enable this on debug mode, though:
public class WicketApplication extends WebApplication {
#Override
public void init() {
super.init();
if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
getDebugSettings().setOutputComponentPath(true);
}
}
}
Extending the RJo's answer.
It seems that the method page.visitChildren(<Class>) is deprecated (Wicket 6), so with an IVisitor it can be :
protected String findPathComponentOnLastRenderedPage(final String idComponent) {
final Page page = wicketTester.getLastRenderedPage();
return page.visitChildren(Component.class, new IVisitor<Component, String>() {
#Override
public void component(final Component component, final IVisit<String> visit) {
if (component.getId().equals(idComponent)) {
visit.stop(component.getPageRelativePath());
}
}
});
}
I have implemented my own editor and added a code completion functionality to it. My content assistant is registered in source viewer configuration like this:
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
if (assistant == null) {
assistant = new ContentAssistant();
assistant.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
assistant.setContentAssistProcessor(getMyAssistProcessor(),
MyPartitionScanner.DESIRED_PARTITION_FOR_MY_ASSISTANCE);
assistant.enableAutoActivation(true);
assistant.setAutoActivationDelay(500);
assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE);
}
return assistant;
}
When I press Ctrl + SPACE inside the desired partition, the completion popup appears and works as expected.
And here's my question.. How do I implement/register a documentation popup that appears next to completion popup? (For example in java editor)
Well,
I'll answear the question myself ;-)
You have to add this line
assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
to the configuration above. Then when creating CompletionProposals, the eighth (last) parameter called additionalProposalInfo of the constructor is the text, which will be shown in the documentation popup.
new CompletionProposal(replacementString,
replacementOffset,
replacementLength,
cursorPosition,
image,
displayString,
contextInformation,
additionalProposalInfo);
More information about can be found here.
Easy, isn't it.. if you know how to do it ;)
For the styled information box (just like in JDT).
The DefaultInformationControl instance need to received a HTMLTextPresenter.
import org.eclipse.jface.internal.text.html.HTMLTextPresenter;
public class MyConfiguration extends SourceViewerConfiguration {
[...]
public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
if (assistant == null) {
[...]
assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
}
return assistant;
}
#Override
public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer) {
return new IInformationControlCreator() {
public IInformationControl createInformationControl(Shell parent) {
return new DefaultInformationControl(parent,new HTMLTextPresenter(false));
}
};
}
}
Proposals can then use basic HTML tags in the string from method getAdditionalProposalInfo().
public class MyProposal implements ICompletionProposal {
[...]
#Override
public String getAdditionalProposalInfo() {
return "<b>Hello</b> <i>World</i>!";
}
}