Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JENKINS-31162] Initial source code modification about Item categoriz…
…ation
  • Loading branch information
Manuel Recena committed Mar 11, 2016
1 parent 8b47f5c commit 09a58b1
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 105 deletions.
34 changes: 34 additions & 0 deletions core/src/main/java/hudson/model/ItemGroupMixIn.java
Expand Up @@ -29,8 +29,13 @@
import hudson.security.AccessControlled;
import hudson.util.CopyOnWriteMap;
import hudson.util.Function1;
import jenkins.model.ItemCategory.Categories;
import jenkins.model.ItemCategory.Category;
import jenkins.model.ItemCategory.ItemCategory;
import jenkins.model.ItemCategory.ItemCategoryConfigurator;
import jenkins.model.Jenkins;
import jenkins.util.xml.XMLUtils;
import org.acegisecurity.Authentication;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

Expand All @@ -44,6 +49,8 @@
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -328,6 +335,33 @@ public synchronized TopLevelItem createProject( TopLevelItemDescriptor type, Str
return item;
}

/**
* Populate a {$link Categories} from a specific {$link ItemGroup}.
*
* @return
*/
public static Categories getCategories(Authentication a, ItemGroup c) {
Categories categories = new Categories();
for (TopLevelItemDescriptor descriptor : Items.all(a, c)) {
ItemCategory ic = ItemCategoryConfigurator.getCategory(descriptor);
int i = 0;
boolean found = false;
while (i < categories.getItems().size() && !found) {
if (categories.getItems().get(i).getId() == ic.getId()) {
categories.getItems().get(i).getItems().add(descriptor.clazz.getName());
found = true;
}
i++;
}
if (!found) {
List<String> descriptors = new ArrayList<String>();
descriptors.add(descriptor.clazz.getName());
categories.getItems().add(new Category(ic.getId(), ic.getDisplayName(), ic.getDescription(), ic.getIconClassName(), descriptors));
}
}
return categories;
}

/**
* Pointless wrapper to avoid HotSpot problem. See JENKINS-5756
*/
Expand Down
12 changes: 11 additions & 1 deletion core/src/main/java/hudson/model/View.java
Expand Up @@ -54,6 +54,7 @@
import hudson.util.XStream2;
import hudson.views.ListViewColumn;
import hudson.widgets.Widget;
import jenkins.model.ItemCategory.Categories;
import jenkins.model.Jenkins;
import jenkins.model.ModelObjectWithChildren;
import jenkins.util.ProgressiveRendering;
Expand Down Expand Up @@ -917,7 +918,7 @@ public SearchIndexBuilder makeSearchIndex() {
SearchIndexBuilder sib = super.makeSearchIndex();
sib.add(new CollectionSearchIndex<TopLevelItem>() {// for jobs in the view
protected TopLevelItem get(String key) { return getItem(key); }
protected Collection<TopLevelItem> all() { return getItems(); }
protected Collection<TopLevelItem> all() { return getItems(); }
@Override
protected String getName(TopLevelItem o) {
// return the name instead of the display for suggestion searching
Expand Down Expand Up @@ -1000,6 +1001,15 @@ public synchronized void doDoDelete(StaplerRequest req, StaplerResponse rsp) thr
*/
public abstract Item doCreateItem( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException;

/**
* A new API method to get the allowed {$link TopLevelItem}s and its categories.
*
* @return A {$Categories} entity that is shown as JSON file.
*/
public Categories doCategories(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
return ItemGroupMixIn.getCategories(Jenkins.getAuthentication(), Jenkins.getInstance());
}

public void doRssAll( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
rss(req, rsp, " all builds", getBuilds());
}
Expand Down
37 changes: 37 additions & 0 deletions core/src/main/java/jenkins/model/ItemCategory/Categories.java
@@ -0,0 +1,37 @@
package jenkins.model.ItemCategory;

import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.export.Flavor;

import javax.servlet.ServletException;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
* It is a logic representation of a set of {$Category}.
*/
@ExportedBean
public class Categories implements HttpResponse, Serializable {

private List<Category> items;

public Categories() {
items = new ArrayList<Category>();
}

@Exported(name = "categories")
public List<Category> getItems() {
return items;
}

@Override
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
rsp.serveExposedBean(req, this, Flavor.JSON);
}
}
59 changes: 59 additions & 0 deletions core/src/main/java/jenkins/model/ItemCategory/Category.java
@@ -0,0 +1,59 @@
package jenkins.model.ItemCategory;

import hudson.model.TopLevelItem;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;

import java.io.Serializable;
import java.util.List;

/**
* Represents an {$link ItemCategory} and its {@link TopLevelItem}s.
*/
@ExportedBean
public class Category implements Serializable {

private String id;

private String name;

private String description;

private String iconClassName;

private List<String> items;

public Category(String id, String name, String description, String iconClassName, List<String> items) {
this.id= id;
this.name = name;
this.description = description;
this.iconClassName = iconClassName;
this.items = items;
}

@Exported
public String getId() {
return id;
}

@Exported
public String getName() {
return name;
}

@Exported
public String getDescription() {
return description;
}

@Exported
public String getIconClassName() {
return iconClassName;
}

@Exported
public List<String> getItems() {
return items;
}

}
@@ -1,54 +1,61 @@
package jenkins.model;
package jenkins.model.ItemCategory;

import hudson.Extension;
import hudson.ExtensionPoint;
import hudson.model.ModelObject;
import jenkins.model.Messages;

/**
* A category for {@link hudson.model.Item}s.
*/
public abstract class ItemCategory implements ModelObject, ExtensionPoint {

/**
* The icon class specification e.g. 'icon-category-folder', 'icon-help' etc.
* The size specification should not be provided as that is determined by the
* context of where the category is displayed.
* Identifier, e.g. "category-id-default", etc.
*
* @return the identifier
*/
public abstract String getId();

/**
* The icon class specification e.g. 'category-icon-folder', 'category-icon-default', etc.
*
* @return the icon class specification
*/
public abstract String getIconClassName();

/**
* The description in plain text
*
* @return the description
*/
public abstract String getDescription();

/**
* The default category, if an item doesn't belong anywhere else, this is where it goes by default.
*/
@Extension
public static final class Default extends ItemCategory {

@Override
public String getIconClassName() {
return "icon-category-default"; //TODO whatever Gus decides
public String getId() {
return "category-id-default";
}

@Override
public String getDisplayName() {
return Messages.ItemCategory_Default_DisplayName();
public String getIconClassName() {
return "category-icon-default";
}
}

/**
* A category suitable for folder and container (not docker) like items.
*/
@Extension
public static final class Folders extends ItemCategory {

@Override
public String getIconClassName() {
return "icon-category-folders"; //TODO whatever Gus decides
public String getDescription() {
return Messages.ItemCategory_Default_Description();
}

@Override
public String getDisplayName() {
return Messages.ItemCategory_Folders_DisplayName();
return Messages.ItemCategory_Default_DisplayName();
}
}

}
@@ -0,0 +1,64 @@
package jenkins.model.ItemCategory;

import hudson.Extension;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.TopLevelItemDescriptor;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.logging.Logger;

/**
* A mapper of {@link ItemCategory}s to {@link hudson.model.Item}s.
*/
public abstract class ItemCategoryConfigurator implements ExtensionPoint {

public static final Logger LOGGER = Logger.getLogger(ItemCategoryConfigurator.class.getName());

/**
* Provides the category for the requested item or null if this mapper doesn't have one.
*
* @param descriptor the item to categorise
*
* @return the category or null
*/
@CheckForNull
protected abstract ItemCategory getCategoryFor(@Nonnull TopLevelItemDescriptor descriptor);

/**
* Finds the category specified by the first mapper.
* If none can be found {@link ItemCategory.Default} is returned.
*
* @param descriptor the item to categorise.
*
* @return the category
*/
@Nonnull
public static ItemCategory getCategory(@Nonnull TopLevelItemDescriptor descriptor) {
for (ItemCategoryConfigurator m : all()) {
ItemCategory category = m.getCategoryFor(descriptor);
if (category != null) {
return category;
}
}
throw new IllegalStateException();
}

public static Collection<ItemCategoryConfigurator> all() {
return ExtensionList.lookup(ItemCategoryConfigurator.class);
}

/**
* Mapper implementation with the lowest ordinal that simply returns {@link ItemCategory.Default}.
*/
@Extension(ordinal = Integer.MIN_VALUE)
public static final class DefaultConfigurator extends ItemCategoryConfigurator {

@Override
public ItemCategory getCategoryFor(@Nonnull TopLevelItemDescriptor descriptor) {
return ExtensionList.lookup(ItemCategory.Default.class).iterator().next();
}
}
}

0 comments on commit 09a58b1

Please sign in to comment.