Author Archives: admin

Nexus – java.io.EOFException: No content to map to Object due to end of input

Sometimes this issue occurs when restarting Nexus [my version is 2.0.5].

The following steps to clean Nexus mostly help to get it up and running again

# Clear archetype-metadata.xml
– Goto /sonatype-work/nexus/storage
– perform the following command “rm **/*/archetype-metadata.xml

# Clear repository-metadata.xml
– Goto /sonatype-work/nexus/storage
– perform the following command “rm **/*/repository-metadata.xml

# Clean .nexus/attributes directories with size 0
– Goto /sonatype-work/nexus/storage
– perform the following command “find . -type f -size 0 |xargs rm”

After this, restart the service via ” sudo service nexus restart”

Setting the soap response header in spring-ws

Filling the response body of a soap message in spring ws is normally well explained on various websites. Figuring out how to also fill the response header took me a bit more investigation.

There are several options, which are described below. First you have to ensure that the messageContext is added as a parameter in the payload. Alternatively you can use a interceptor.

    @PayloadRoot(localPart = LOCAL_PART, namespace = NAMESPACE)
    @ResponsePayload
    public <return type> handleRequest(@RequestPayload final <request type> request,
                                                 MessageContext messageContext) {

With this messageContext you can set the response header the following ways.

Fill the response header 1-on-1 the same as the request header
The following will get the request header from the message context at puts that back exactly the same in the response header.

    
    public void appendHeader(MessageContext messageContext ){
        SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext.getRequest();
        SoapHeader reqheader = soapRequest.getSoapHeader();
        SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
        SoapHeader respheader = soapResponse.getSoapHeader();
 
        try {
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            Iterator<SoapHeaderElement> itr = reqheader.examineAllHeaderElements();
            while (itr.hasNext()) {
                SoapHeaderElement ele = itr.next();
                transformer.transform(ele.getSource(), respheader.getResult());
            }
        } catch (TransformerException e) {
            LOG.error("error adding header", e);
        }
    }

(Un)marshall the response header from it’s object type
The following code will get you the unmarshalled request header object, which will give you the opportunity to use it’s getters and setters.

Note that you have to replace the in below example code with the class name of your own response header object.

public void appendHeader(MessageContext messageContext ){
        
        SaajSoapMessage soapRequest = (SaajSoapMessage) messageContext.getRequest();
        SoapHeader reqheader = soapRequest.getSoapHeader();
        SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
        SoapHeader respheader = soapResponse.getSoapHeader();
 
        Iterator<SoapHeaderElement> itr = reqheader.examineAllHeaderElements();
        while (itr.hasNext()) {
            SoapHeaderElement ele = itr.next();
 
            try {
                JAXBContext context = JAXBContext.newInstance(<T>.class);
                Unmarshaller unmarshaller = context.createUnmarshaller();
                Marshaller marshaller = context.createMarshaller();
 
                <T> headerType = unmarshaller.unmarshal(ele.getSource(), <T>.class).getValue();
                headerType.setRelatesTo(auditHeaderType.getMessageID());
 
                JAXBElement<T> responseHeader = new JAXBElement<T>(ele.getName(), <T>, headerType);
                marshaller.marshal(responseHeader, respheader.getResult());
 
            } catch (JAXBException e) {
                throw new RuntimeException(e);
            }
        }
    }

Creating a dynamic menu in an Atlassian plugin

When you want to generate a menu item for your Jira plugin you can use the following sample. This enables you to group menu item [this separates them with a horizontal line] and enables you to specify conditions on when menu items should be shown.

The below code will present the following menu item.

Schermafbeelding 2014-05-11 om 19.03.02

Step 1: Specify web-section, web-item and simple-link-factory in the atlassian-plugin.xml
The web-item on the root level gets the location “system.top.navigation.bar”. This places the menu item in the top menu bar of Jira. In this example it is called “Planning”.

This root level web-item consists of web-section items and web-items, and are referred to via the attribute “location”. A web-section can refer to a simple-link-factory, which is a Java class in which logic can be entered when menu item should or should not be shown.

    <web-section key="menu_section_recent" name="Menu Section" location="menu_link" weight="10">
        <label key="menu.forecast.recent"/>
    </web-section>

    <web-section key="menu_section_favourite" name="Menu Section" location="menu_link" weight="10">
        <label key="menu.forecast.favourite"/>
    </web-section>

    <web-section key="menu_section_general" name="Menu Section" location="menu_link" weight="10"/>

    <web-item key="menu_link" name="Instances" section="system.top.navigation.bar" weight="47">
        <label key="menu.forecast.planning"/>
        <link linkId="menu_link">http://www.geertjan.it</link>
    </web-item>

    <web-item key="manage_forecasts_link" name="Overview of all forecasts" section="menu_link/menu_section_general" weight="10">
        <label key="menu.forecast.manage"/>
        <link linkId="manage_forecasts_link">/plugins/servlet/planning-forecast/viewForecasts</link>
    </web-item>

    <web-item key="started_link" name="Getting started" section="menu_link/menu_section_general" weight="10">
        <label key="menu.forecast.start"/>
        <link linkId="started_link">/plugins/servlet/planning-forecast/start</link>
    </web-item>

    <!-- dynamic web item -->
    <simple-link-factory key="dynamic-factory-current" name="Dynamic Link Factory" section="menu_link/menu_section_current"
                         i18n-name-key="Dynamic menu" weight="30" lazy="true"
                         class="com.gjdb.plugins.jira.factory.DynamicLinkFactory"/>

    <simple-link-factory key="dynamic-factory-recent" name="Dynamic Link Factory" section="menu_link/menu_section_recent"
                         i18n-name-key="Dynamic menu" weight="30" lazy="true"
                         class="com.gjdb.plugins.jira.factory.DynamicLinkFactory"/>

    <simple-link-factory key="dynamic-factory-favourite" name="Dynamic Link Factory" section="menu_link/menu_section_favourite"
                         i18n-name-key="Dynamic menu" weight="30" lazy="true"
                         class="com.gjdb.plugins.jira.factory.DynamicLinkFactory"/>

Step 2: Implement the simple-link-factory

package com.gjdb.plugins.jira.factory;

import com.atlassian.crowd.embedded.api.User;
import com.atlassian.jira.plugin.webfragment.SimpleLinkFactory;
import com.atlassian.jira.plugin.webfragment.descriptors.SimpleLinkFactoryModuleDescriptor;
import com.atlassian.jira.plugin.webfragment.model.SimpleLink;
import com.atlassian.jira.plugin.webfragment.model.SimpleLinkImpl;
import com.gjdb.plugins.jira.model.Forecast;
import com.gjdb.plugins.jira.repository.ForecastRepository;
import com.gjdb.plugins.jira.util.UserUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author GJDB
 */
public class DynamicLinkFactory implements SimpleLinkFactory {

    private String section;

    public DynamicLinkFactory() {

    }

    /* (non-Javadoc)
         * @see com.atlassian.jira.plugin.webfragment.SimpleLinkFactory#getLinks(com.atlassian.crowd.embedded.api.User, java.util.Map)
         */
    @Override
    public List<SimpleLink> getLinks(User user, Map<String, Object> map) {
        List<SimpleLink> links = new ArrayList<SimpleLink>();

        if("menu_link/menu_section_recent".equals(section)) {
            links.add(new SimpleLinkImpl("recent-" + key, forecast.getDescription(), forecast.getDescription(), null, null, "/jira/plugins/servlet/planning-forecast/instance?key=" + key, null));
            }

        <logic for other menu sections removed>

        return links;
    }

    /* (non-Javadoc)
     * @see com.atlassian.jira.plugin.webfragment.SimpleLinkFactory#init(com.atlassian.jira.plugin.webfragment.descriptors.SimpleLinkFactoryModuleDescriptor)
     */
    @Override
    public void init(SimpleLinkFactoryModuleDescriptor simDescriptor) {
        section = simDescriptor.getSection();
    }

}

Analyzing java.io.FileNotFoundException on HttpURLConnection

Just tried to open a HttpURLConnection, but that did not go well initially. A very unclear ” java.io.FileNotFoundException ” error was thrown.

So how to analyze why this happens? First check the response code [connection.getResponseCode()], otherwise open the connection.getErrorStream(); instead of the is = connection.getInputStream();

In my case it told me that authentication had to be done first

{"errorMessages":["The requested board cannot be viewed because it either does not exist or you do not have permission to view it."],"errors":{}}

So after adding basic authentication the error was fixed and I got the required response! Here the code:

    public static String readURLWithConnection(String urlString) throws Exception {
        HttpURLConnection connection;
        InputStream is;
        URL url = new URL(urlString);
        
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
        connection.setRequestProperty("Accept", "*/*");

        String userpass = "admin:admin";
        String basicAuth = "Basic " + new String(new Base64().encode(userpass.getBytes()));
        connection.setRequestProperty ("Authorization", basicAuth);

        connection.connect();
        try {
            is = connection.getInputStream();
        } catch(FileNotFoundException exception){
            log.error(exception.getMessage(), exception);
            is = connection.getErrorStream();
        }

        BufferedReader theReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        StringBuilder response = new StringBuilder();
        String reply;
        while ((reply = theReader.readLine()) != null) {
            response.append(reply);
        }

        return response.toString();
    }

Create a Rest service in a Jira Atlassian plugin

Traditionally a user fills in a form in a webpage and has to actively press a save button in order to have the data stored. This has two main disadvantages: 1) this communication is normally done via http, which is much slower then a rest service cause it has much more overhead 2) a user nowadays expects direct feedback and expects a website to store data actively by itself.

Herefore a restfull service can be used, the following article describes how to enable a rest service within your own Jira Atlassian plugin.

Step 1: add a rest declaration to the atlassian-plugin.xml
The path element sets the context root to which all rest resources for your plugin will listen.

    <rest key="rest" path="/planning-forecast-overview" version="1.0">
        <description>Provides REST resources for the overview UI.</description>
    </rest>

So, by the end of this example the rest service can be called as followed:
Schermafbeelding 2014-05-11 om 19.49.36

Step 2: Have a script trigger a rest call to the server
The following script is normally triggered by a click event, and sends a rest call to the server.

    function upsertClaim(value, span) {
        var spanId = span.getAttribute("id");
        var ids = spanId.split("-+-");

        AJS.$.ajax({
            url: baseUrl + "/rest/planning-forecast-overview/1.0/upsertClaim?issueId=" + ids[0] + "&periodId="+ ids[1]
                + "&value=" + value + "&forecastKey=" + getRequestParam("key"),
            dataType: "json",
            success: function(filter) {
                setSpanValue(span, value);
            }
        });

    }

Step 3: Add a Java class to process the restfull calls.
This particular example does not sent a response object, but this is also possible. This response would be in the “success” variable as a parameter.

package com.gjdb.plugins.jira.resources;

import com.atlassian.sal.api.transaction.TransactionCallback;
import com.atlassian.sal.api.transaction.TransactionTemplate;
import com.gjdb.plugins.jira.model.Claim;
import com.gjdb.plugins.jira.model.ClaimStatus;
import com.gjdb.plugins.jira.model.Forecast;
import com.gjdb.plugins.jira.repository.ForecastRepository;
import com.gjdb.plugins.jira.util.UserUtil;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

/**
 * @author GJDB
 */
@Path("/upsertClaim")
public class UpsertClaimResource {

    private final TransactionTemplate transactionTemplate;

    public UpsertClaimResource(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response get(@Context final HttpServletRequest request) {
        if(!UserUtil.allowAccess(request, UserUtil.getAdminUserGroups())) {
            return Response.status(Response.Status.UNAUTHORIZED).build();
        }

        return Response.ok(transactionTemplate.execute(new TransactionCallback() {
            public Object doInTransaction() {
            final String issueId = request.getParameter("issueId");
           
            <logic removed for this blog>
 
            return null;
            }
        })).build();
    }
  
}

Result
When you monitor the traffic between the browser and the server, you should see something like the following when on a [click] event a rest call is being performed. Note that a 200 response means it is processed without errors.

Schermafbeelding 2014-05-11 om 19.50.04