Is there any way to hide the version of vaadin version (i.e v=7.6.2) in page source? Also is it possible to change the default directory "VAADIN" to any other directory or rename it?
I think it is impossible to get rid of VAADIN directory name because it is hardcoded in some framework classes on server and client side. For example: com.vaadin.server.BootstrapHandler, com.vaadin.server.VaadinServlet and com.vaadin.client.ui.ui.UIConnector
Technically speaking it is possible to hide Vaadin version. All you need is to register BootstrapListener at the start of Servlet session
public class ApplicationBootstrapListener implements BootstrapListener {
#Override
public void modifyBootstrapFragment(BootstrapFragmentResponse response) {
List<Node> nodes = response.getFragmentNodes();
for (Node node : nodes) {
if (node.toString()
.contains("js?v=")) {
String fakeVersion = node.attr("src")
.replace("7.5.8", "1.1.1");
node.attributes()
.put("src", fakeVersion);
}
}
}
#Override
public void modifyBootstrapPage(BootstrapPageResponse response) {
}
}
//somewhere in servletInitialized()
getService().addSessionInitListener(event -> event.getSession()
.addBootstrapListener(
new ApplicationBootstrapListener()));
After this step application should stop working though. That's because Vaadin won't be able to find vaadinBootstrap.js since you has changed its name. You may need to copy the content of this JavaScript, put it somewhere in the public folder and rename it to whatever fake name you want (in my case it would be vaadinBootstrap.js?v=1.1.1.
As for the second question, I also think it is impossible, at least without a help of reverse engineering.
Building on Kuki's answer, this worked for me on Vaadin 8.9.4, no need to copy any js-file.
#Override
public void modifyBootstrapFragment(BootstrapFragmentResponse bootstrapFragmentResponse) {
final List<Node> nodes = bootstrapFragmentResponse.getFragmentNodes();
final String oldVersion = "8.9.4";
final String fakeVersion = "x.y.z";
for (Node node : nodes) {
/* replacing the version in src-attributes */
if (node.attr("src").contains(oldVersion)) {
node.attributes().put("src", node.attr("src").replace(oldVersion, fakeVersion));
}
/* replacing the version in the child-DataNodes */
for (Node child : node.childNodes()) {
if (child instanceof DataNode) {
final DataNode dataNode = ((DataNode) child);
if (dataNode.getWholeData().contains(oldVersion)) {
dataNode.setWholeData(dataNode.getWholeData().replace(oldVersion, fakeVersion));
}
}
}
}
}
Related
I am working on an xtext Project where I have to customize the Scope Provider. I need to add up some possible candidates for the scope. The first part (getServiceInputs()) works fine but for the second one (addAll(sub.GetSubRecipeParameters()) not. Debugging showed that they get removed from its original source (sub) and can therefore not be retrieved again. When simply commenting out the addAll line the SubRecipeParameters remain in sub. Really dont know how to solve that, tried already some work arounds. Anyone with an Idea?
public class AutomationServiceDslScopeProvider extends AbstractAutomationServiceDslScopeProvider {
#Override
public IScope getScope(EObject context, EReference reference) {
if (context instanceof ServiceInvocationParameter
&& reference == AutomationServiceDslPackage.Literals.LITERAL) {
ServiceInvocation serviceCall = (ServiceInvocation) invocationParameter.eContainer();
ServiceDefinition calledService = serviceCall.getService();
List<ServiceParameterDefinition> candidates= calledService.getServiceInputs();
final EObject rootContainer = EcoreUtil.getRootContainer(context);
List<SubRecipeDefinition> subs = EcoreUtil2.getAllContentsOfType(rootContainer, SubRecipeDefinition.class);
for(SubRecipeDefinition sub:subs) {
for(RecipeStep step:sub.getRecipeSteps()) {
if(step.getName()==serviceCall.getName()) {
candidates.addAll(sub.getSubRecipeParameters());
}
}
}
return Scopes.scopeFor(candidates);
Thanks for any help!!
This is normal EMF behaviour if you move elements from one EList to another one. The solution is to create a new list e.g. new ArrayList<>() and also add the inputs there
List<ServiceParameterDefinition> candidates = new ArrayList<>();
candidates.addAll(calledService.getServiceInputs());
For a custom monitoring tool I need an API (REST) to fetch the console log of a Jenkins build in chunks.
I know about the /consoleText and /logText/progressive{Text|HTML} APIs, but the problem with this is that sometimes, our build logs get really huge (up to a few GB). I have not found any way using those existing APIs that avoids fetching and transferring the whole log in one piece. This then normally drives the Jenkins master out of memory.
I already have the Java code to efficiently fetch chunks from a file, and I have a basic Jenkins plugin that gets loaded correctly.
What I'm missing is the correct extension point so that I could call my plugin via REST, for example like
http://.../jenkins/job/<jobname>/<buildnr>/myPlugin/logChunk?start=1000&size=1000
Or also, if that is easier
http://.../jenkins/myPlugin/logChunk?start=1000&size=1000&job=<jobName>&build=<buildNr>
I tried to register my plugin with something like (that code below does not work!!)
#Extension
public class JobLogReaderAPI extends TransientActionFactory<T> implements Action {
public void doLogChunk(StaplerRequest req, StaplerResponse rsp) throws IOException {
LOGGER.log(Level.INFO, "## doLogFragment req: {}", req);
LOGGER.log(Level.INFO, "## doLogFragment rsp: {}", rsp);
}
But I failed to find the right encantation to register my plugin action.
Any tips or pointers to existing plugins where I can check how to register this?
This was indeed more simple than I expected :-) It as always: once one understands the plugin system, it just needs a few lines of code.
Turns out all I needed to do was write 2 very simple classes
The "action factory" that get's called by Jenkins and registers an action on the object in question (in my case a "build" or "run"
public class ActionFactory extends TransientBuildActionFactory {
public Collection<? extends Action> createFor(Run target) {
ArrayList<Action> actions = new ArrayList<Action>();
if (target.getLogFile().exists()) {
LogChunkReader newAction = new LogChunkReader(target);
actions.add(newAction);
}
return actions;
}
The class the implements the logic
public class LogChunkReader implements Action {
private Run build;
public LogChunkReader(Run build) {
this.build = build;
}
public String getIconFileName() {
return null;
}
public String getDisplayName() {
return null;
}
public String getUrlName() {
return "logChunk";
}
public Run getBuild() {
return build;
}
public void doReadChunk(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
Vaadin 8.1 introduced the TreeGrid component. It does not have the collapseItemsRecursively and expandItemsRecursively methods anymore (as available in the now legacy Tree component). Do i miss something or do you need to develop your own implementation? If so, what is a recommended way of doing this?
As I'm sure you've noticed, the TreeGrid is a rather new component, currently being developed and available starting with v8.1.alphaX (current stable version is v8.0.6). As such, it probably has only some basic functionalities for the time being, with the rest to follow sometime in the future, although there are no guarantee. For example this similar feature request for the older TreeTable component has been in open state since 2011.
Either way, even if they're probably not the optimum solutions, there are a couple of work-arounds that you can use to achieve this behavior. I'm shamelessly using as a base sample, a slightly modified version of the code currently available in the vaadin-sampler for TreeGrid.
public class RecursiveExpansionTreeGrid extends VerticalLayout {
private Random random = new Random();
public RecursiveExpansionTreeGrid() {
// common setup with some dummy data
TreeGrid<Project> treeGrid = new TreeGrid<>();
treeGrid.setItems(generateProjectsForYears(2010, 2016), Project::getSubProjects);
treeGrid.addColumn(Project::getName).setCaption("Project Name").setId("name-column");
treeGrid.addColumn(Project::getHoursDone).setCaption("Hours Done");
treeGrid.addColumn(Project::getLastModified).setCaption("Last Modified");
addComponent(treeGrid);
}
// generate some dummy data to display in the tree grid
private List<Project> generateProjectsForYears(int startYear, int endYear) {
List<Project> projects = new ArrayList<>();
for (int year = startYear; year <= endYear; year++) {
Project yearProject = new Project("Year " + year);
for (int i = 1; i < 2 + random.nextInt(5); i++) {
Project customerProject = new Project("Customer Project " + i);
customerProject.setSubProjects(Arrays.asList(
new LeafProject("Implementation", random.nextInt(100), year),
new LeafProject("Planning", random.nextInt(10), year),
new LeafProject("Prototyping", random.nextInt(20), year)));
yearProject.addSubProject(customerProject);
}
projects.add(yearProject);
}
return projects;
}
// POJO for easy binding
public class Project {
private List<Project> subProjects = new ArrayList<>();
private String name;
public Project(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Project> getSubProjects() {
return subProjects;
}
public void setSubProjects(List<Project> subProjects) {
this.subProjects = subProjects;
}
public void addSubProject(Project subProject) {
subProjects.add(subProject);
}
public int getHoursDone() {
return getSubProjects().stream().map(project -> project.getHoursDone()).reduce(0, Integer::sum);
}
public Date getLastModified() {
return getSubProjects().stream().map(project -> project.getLastModified()).max(Date::compareTo).orElse(null);
}
}
// Second POJO for easy binding
public class LeafProject extends Project {
private int hoursDone;
private Date lastModified;
public LeafProject(String name, int hoursDone, int year) {
super(name);
this.hoursDone = hoursDone;
lastModified = new Date(year - 1900, random.nextInt(12), random.nextInt(10));
}
#Override
public int getHoursDone() {
return hoursDone;
}
#Override
public Date getLastModified() {
return lastModified;
}
}
}
Next, recursively expanding or collapsing the nodes depends a bit on your scenario, but basically it breaks down to the same thing: making sure each node from the root to the deepest leaf is expanded/collapsed.The simplest way of doing it is to flatten your hierarchy into a list of nodes, and call the appropriate method, expand(List<T> items) or expand(T ... items) (the second delegates to the first and is probably a convenience method eg expand(myItem)).
For simplicity, I've added a flatten method in our Project implementation. If you can't do that for some reason, then create a recursive method that creates a list starting with the selected node and includes all the children, of the children, of the children.... well, you get the idea.
public Stream<Project> flatten() {
return Stream.concat(Stream.of(this), getSubProjects().stream().flatMap(Project::flatten));
}
Possible scenarios:
Automatically expand the entire hierarchy when expanding the root - add listeners, and expand/collapse the whole flattened hierarchy:
treeGrid.addCollapseListener(event -> {
if (event.isUserOriginated()) {
// event is triggered by all collapse calls, so only do it the first time, when the user clicks in the UI
// and ignore the programmatic calls
treeGrid.collapse(event.getCollapsedItem().flatten().collect(Collectors.toList()));
}
});
treeGrid.addExpandListener(event -> {
if (event.isUserOriginated()) {
// event is triggered by all expand calls, so only do it the first time, when the user clicks in the UI
// and ignore the programmatic calls
treeGrid.expand(event.getExpandedItem().flatten().collect(Collectors.toList()));
}
});
Expanding the hierarchy or part of it with a custom action, such as a context menu
GridContextMenu<Project> contextMenu = new GridContextMenu<>(treeGrid);
contextMenu.addGridBodyContextMenuListener(contextEvent -> {
contextMenu.removeItems();
if (contextEvent.getItem() != null) {
Project project = (Project) contextEvent.getItem();
// update selection
treeGrid.select(project);
// show option for expanding
contextMenu.addItem("Expand all", VaadinIcons.PLUS, event -> treeGrid.expand((project).flatten().collect(Collectors.toList())));
// show option for collapsing
contextMenu.addItem("Collapse all", VaadinIcons.MINUS, event -> treeGrid.collapse((project).flatten().collect(Collectors.toList())));
}
});
In the end, you should be getting this effect:
From the docs for treegrid, you can use the methods, collapse and expand, by passing a list or array of the treegrid's data items to expand or collapse:
treeGrid.expand(someTreeGridItem1, someTreeGridItem2);
treeGrid.collapse(someTreeGridItem1);
Also worthy of note, is a section showing the ability to prevent certain items from ever being collapsed
I have developed an application. I want to display a message before the user starts implementing my application. Like when it is used first time i want to show "Count = 1". And when app is visited second time, "Count = 2".
How can i achieve it? I had done such thing in android using sharedperferences. But how can i do it in blackberry. I had tried something with PersistentStore. But cant achieve that, for i dont know anything about the Persistance in BB.
Also i would wish to restrict the use for 100. Is it possible?
sample codes for this will be appreciable, since i am new to this environment..
You can achieve it with Persistent Storage.
Check this nice tutorial about storing persistent data.
Also you can use SQLite. Link to a development guide which describes how to use SQLite databases in Java® applications: Storing data in SQLite databases.
You can restrict user for trying your application at most 100 times using your own logic with the help of persistent data. But I think there may be some convention, so try Google for that.
got it...
I created a new class which implements Persistable. In that class i had created an integer variable and set an getter and setter function for that integer...
import net.rim.device.api.util.Persistable;
public class Persist implements Persistable
{
private int first;
public int getCount()
{
return first;
}
public void setCount()
{
this.first += 1;
}
}
Then in the class which initializes my screen, i had declared persistence variables and 3 functions to use my Persist.java, initStore(), savePersist(), and getPersist()
public final class MyScreen extends MainScreen implements FieldChangeListener
{
/*
* Declaring my variables...
*/
private static PersistentObject store;
public Persist p;
public MyScreen()
{
//my application codes
//here uses persistence
initStore();
p = getPersist();
if(p.getCount()<100)
{
savePersist();
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert(p.getCount.toString());
}
});
}
else
{
close();
System.exit(0);
}
}
//three function....
public static void initStore()
{
store = PersistentStore.getPersistentObject(0x4612d496ef1ecce8L);
}
public void savePersist()
{
synchronized (store)
{
p.setCount();
store.setContents(p);
store.commit();
}
}
public Persist getPersist()
{
Persist p = new Persist();
synchronized(store)
{
p = (Persist)store.getContents();
if(p==null)
{
p = new Persist();
}
}
return p;
}
}
I hope u all will get it right now....
If there are another simple way, plz let me know...
Thanks
I would like to prevent content nodes from being trashed if they have any children. I setup an event handler like so:
public class KeepSafeEvents : ApplicationBase
{
public KeepSafeEvents()
{
Document.BeforeMoveToTrash += new Document.MoveToTrashEventHandler(Document_BeforeMoveToTrash);
}
void Document_BeforeMoveToTrash(Document sender, umbraco.cms.businesslogic.MoveToTrashEventArgs e)
{
if (sender.HasChildren)
{
e.Cancel = true;
}
}
}
However, this doesn't seem to work. I assume it is because the delete process moves the child nodes to trash first before dealing with the parent node (which then has no children). Is there another possible solution? Or am I making a simple mistake above?
This code works perfectly for me. Are you sure that you've copied the resulting .dll file to Umbraco's /bin folder?
I just wrote it a little shorter than you did, like below, but the functionality should be exactly the same.
I do notice that the document with childnode seems to get deleted (it disappears from the tree), but when you reload the tree, the node is still there.
public class KeepSafeEvents : ApplicationBase
{
public KeepSafeEvents()
{
Document.BeforeMoveToTrash += Document_BeforeMoveToTrash;
}
void Document_BeforeMoveToTrash(Document sender, MoveToTrashEventArgs e)
{
if (sender.HasChildren)
e.Cancel = true;
}
}