runlevel3

What to do when there’s no space left on device (boot partition)

First identify your current kernel with

uname -r

then list all other kernel images you have installed (except your current)

dpkg -l linux-{image,headers}-“[0-9]*” | awk ‘/^ii/{ print $2}’ | grep -v -e uname -r | cut -f1,2 -d"-" | grep -e ‘[0-9]’

you can try to remove them with the following command

dpkg -l linux-{image,headers}-“[0-9]*” | awk ‘/^ii/{ print $2}’ | grep -v -e uname -r | cut -f1,2 -d"-" | grep -e ‘[0-9]’ | xargs sudo apt-get -y purge

if that doesn’t work, you could try to remove them manually.

Identify kernel images you may remove with

sudo dpkg –list ‘linux-image*’|awk ‘{ if ($1==”ii”) print $2}’|grep -v uname -r

remove the files with using the older versions and, perhaps, leaving out the last 2 versions for having an option in case you need to boot with a previous kernel

rm -rf /boot/-4.4.0-{47,51,53,57}

fix missing dependencies with

sudo apt-get -f install

and finally clean up with

sudo apt-get autoremove

fuentes:
https://askubuntu.com/questions/89710/how-do-i-free-up-more-space-in-boot
https://askubuntu.com/questions/345588/what-is-the-safest-way-to-clean-up-boot-partition

Anuncios

Supongamos que tienes un reporte en el que quieres ocultar un listado de una consulta de acuerdo al valor de un parámetro.

Podríamos ocultarlo fácilmente mediante la opción de visibilidad ‘Properties | Visibility | Hide element’ y utilizar una expresión como la siguiente

params[‘ocultarDetalles’].value === true

Screenshot from 2017-06-23 15-02-13

pero la consulta se ejecutaría de cualquier manera, lo que ocasionaría tiempo y procesamiento innecesario.

Para que no se ejecuté la consulta, es necesario remover el elemento que queremos ocultar en el método ‘beforeFactory’ del reporte. Para ello, primero necesitamos especificar el nombre al elemento que queremos ocultar, yo utilicé un grid el cual contiene la tabla de la consulta y lo nombré grdDetalles.
Screenshot from 2017-06-23 15-28-46

Luego selecciona la pestaña ‘Script’ y en la ventana ‘Outline’ selecciona el reporte. Asegurate seleccionar el evento ‘beforeFactory’ y agrega el siguiente script

if (params['ocultarDetalles'].value === true) {
    reportContext.getDesignHandle().findElement("grdDetalles").drop();
}

Screenshot from 2017-06-23 15-01-23

con esto se evita que se realice innecesariamente la consulta.

fuentes:
http://developer.actuate.com/community/forum/index.php?/topic/34143-does-birt-still-execute-a-query-if-an-element-is-hidden/

While I was working with a lot of reports, it made sense to use a standard file name for all the files. This was an afterthought, so it required me to rename the files. I was hoping Ubuntu Nautilus had this option, but for my current version -16.04- it doesn’t. That feature is expected to land in 17.04. in the meantime you can install nautilus-renamer which offers the same feature.

Just download the .deb package from the nautilus-renamer launchpad page and install it with

sudo dpkg -i nautilus-renamer_4.0-quantal_all.deb
sudo apt install -f
killall nautilus

It des not work if parent folders contain spaces in their name and it does not support unicode characters. I guess the nautilus version for 17.04 should work with these.

Then, just open a nautilus window and select a bunch of files, right click and select ‘rename…’ or just press F2.

done!

sources:
http://www.omgubuntu.co.uk/2016/06/nautilus-batch-rename-feature-coming-gnome-3-22
https://launchpad.net/nautilus-renamer
http://www.omgubuntu.co.uk/2016/08/quick-look-new-features-nautilus-3-22
https://launchpad.net/~gnome3-team/+archive/ubuntu/gnome3

We have a bunch of tables per office, each on its own schema in an Oracle Database.

For simplicity, we have created views on this tables and synonyms to access this views from one single schema. Hibernate supports mapping entities to synonyms, so there’s nothing more we need to do on our entities. But we still want to be able to add and modify underlying data.

To achieve this we had to create views and triggers like so

SET DEFINE OFF;
CREATE OR REPLACE FORCE VIEW CENTRAL.VPARTES
(
   SID_PARTE,
   ...
)
AS
   SELECT 'OF001' SID_OFICINA,
          T.SID_PARTE,
          ...
     FROM OFICINA001.TPARTES T
    WHERE 1 = 1 AND T.NESTATUS IN (1, 2)
   UNION ALL
   SELECT 'OF002' SID_OFICINA,
          T.SID_PARTE,
          ...
     FROM OFICINA002.TPARTES T
    WHERE 1 = 1 AND T.NESTATUS IN (1, 2);


CREATE OR REPLACE TRIGGER CENTRAL.TG_VPARTES_UPD
INSTEAD OF UPDATE
ON CENTRAL.VPARTES
FOR EACH ROW
BEGIN
IF :OLD.SID_OFICINA = 'OF001' THEN
UPDATE OFICINA001.TPARTES
SET    
       SESTATUS       = :NEW.SESTATUS,
       ...
WHERE  1 = 1
AND SID_PARTE        = :NEW.SID_PARTE ;
ELSIF :OLD.SID_OFICINA = 'OF002' THEN 
UPDATE OFICINA002.TPARTES
SET    
       SESTATUS       = :NEW.SESTATUS,
       ...
WHERE  1 = 1
AND SID_PARTE        = :NEW.SID_PARTE ;
END IF;
END;
/

for the INSERT it would be kind of the same.

If you happen to use JHipster, to allow the usage of synonyms while passing the liquibase validation we need to add a hibernate property on our corresponding application-{profile}.yml or disable liquibase altogether.

spring:
    profiles:
        include: no-liquibase
...
    jpa:
        database-platform: org.hibernate.dialect.Oracle12cDialect
        database: ORACLE
        show-sql: false
        properties:
            ...
            hibernate.synonyms: true

sources:
http://stackoverflow.com/questions/6531729/updatable-view-oracle
http://stackoverflow.com/questions/8817253/jpa-entiy-on-synonym-instead-of-table

JHipster is a great tool to start and develop applications, it follows best practices and includes best of breed frameworks and tools.

But, at first it could be too complex to understand. One of the tough things to grasp is liquibase. For us, we had been used to design and build the tables first and then our entities. With jhipster it takes only one step, create your entities and liquibase will take care of the rest. I totally understand why it’s included (they recommend best practices remember), changes to the database are part of any system and as such they should be included as part of the application -and version control, of course-.

To ease the adoption of this tool, we disabled liquibase on production by adding just this lines to the application-prod.yml file

spring:
    profiles:
        include: no-liquibase
...

sources:
http://stackoverflow.com/questions/34559042/disable-liquibase-temporarily-in-jhipster-2-26

To integrate a REST web service with SmartGWT DataSource you have client side data integration mechanisms.

I’ve used this to connect an existing REST web service with SmartGWT controls.

Nevertheless, we have a REST web service wich receives a Path Parameter to update an entity.

    @PUT
    @Path("/proveedores/{id}")
    public Response updateProveedor(@PathParam("id")String id, String request){
        Response response = null;
        try{
            SCRequest<Proveedor> scRequest = Jackson.mapper().readValue(request, new TypeReference<SCRequest<Proveedor>>() {
            });
            Proveedor proveedor = Proveedor.guardar(scRequest.getData());
            response = Response.ok(Jackson.mapper().writeValueAsString(new SCResponse(0, proveedor))).build();
        } catch (Exception e){
            String error = "Ocurrio un problema al actualizar el registro del proveedor";
            log.error(error, e);
            response = Response.serverError().entity(error).build();
        }
        return response;
    }

we need to configure the URL of the RestDataSource dynamically like so in the transformRequest method

public class ProveedoresRestDataSource extends RestDataSource {
    private static final Logger log = Logger.getLogger("ProveedoresRestDataSource");

    public static final ProveedoresRestDataSource INSTANCE = new ProveedoresRestDataSource();
    public static final String API_REST_WEB_GWT_COMPRAS_CATALOGOS_PROVEEDORES = "api/rest/web-gwt-compras/catalogos/proveedores";

    public ProveedoresRestDataSource() {
        setDataURL(API_REST_WEB_GWT_COMPRAS_CATALOGOS_PROVEEDORES);
        setDataFormat(DSDataFormat.JSON);

        OperationBinding create = new OperationBinding(DSOperationType.ADD, API_REST_WEB_GWT_COMPRAS_CATALOGOS_PROVEEDORES);
        create.setDataProtocol(DSProtocol.POSTMESSAGE);
        OperationBinding retrieve = new OperationBinding(DSOperationType.FETCH, API_REST_WEB_GWT_COMPRAS_CATALOGOS_PROVEEDORES);
        OperationBinding update = new OperationBinding(DSOperationType.UPDATE, API_REST_WEB_GWT_COMPRAS_CATALOGOS_PROVEEDORES);
        update.setDataProtocol(DSProtocol.POSTMESSAGE);
        DSRequest updateProperties = new DSRequest();
        updateProperties.setHttpMethod("PUT");
        update.setRequestProperties(updateProperties);
        setOperationBindings(create, retrieve, update);

        DataSourceField fldId = new DataSourceTextField("id");
        fldId.setPrimaryKey(true);
...
        setFields(fldId, ...);
    }

    @Override
    protected Object transformRequest(DSRequest dsRequest) {
        if(DSOperationType.UPDATE.equals(dsRequest.getOperationType())){
            String id = JSOHelper.getAttribute(dsRequest.getData(), "id");
            dsRequest.setActionURL(API_REST_WEB_GWT_COMPRAS_CATALOGOS_PROVEEDORES + "/" + id);
        }
        return super.transformRequest(dsRequest);
    }
}

sources:
http://helpdesk.objects.com.au/java/how-do-i-generate-dynamic-urls-with-smartgwt-and-restdatasource
http://www.smartclient.com/smartgwt/javadoc/

It has been a long time since I updated an app which we have developed with SmartGWT. This time we needed to upload a file to update some catalog.

The SmartGWT documentation explains different ways to achieve this, we’re interested in this part

Background upload without the Smart GWT Server

Achieving background file upload without using the Smart GWT server is also possible although considerably more advanced. In addition to the steps above, create a hidden ** element in the page, and **use DynamicForm.target to target the form submission at this IFRAME. In order receive a callback notification when the upload completes, after processing the file upload, your server should output HTML content for the IFRAME that includes a block which will navigate out of the IFRAME (generally via the JavaScript global “top”) and call a global method you have declared as a callback.

So, the first thing we are going to need is the server side service to receive such file. This app had REST web services with Apache CXF already working, so we should use this same framework (credit goes to javatips for this).

import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.activation.DataHandler;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.List;

@Path("catalogos")
public class CatalogosREST {
    private final Logger log = LoggerFactory.getLogger(CatalogosREST.class);

    private String getFileName(MultivaluedMap<String, String> header) {
        String[] contentDisposition = header.getFirst("Content-Disposition").split(";");
        for (String filename : contentDisposition) {
            if ((filename.trim().startsWith("filename"))) {
                String[] name = filename.split("=");
                String exactFileName = name[1].trim().replaceAll("\"", "");
                return exactFileName;
            }
        }
        return "unknown";
    }

    @POST
    @Path("/upload")
    @Consumes("multipart/form-data")
    public Response uploadFile(List<Attachment> attachments, @Context HttpServletRequest request) {
        log.debug("se ha recibido una peticion para subir un archivo de proveedores [attachments: {}, request: {}]", attachments, request);
        Response response = null;
        for (Attachment attachment : attachments) {
            DataHandler handler = attachment.getDataHandler();
            try {
                InputStream stream = handler.getInputStream();
                MultivaluedMap<String, String> map = attachment.getHeaders();
                log.debug("headers: {}", map);
                log.debug("fileName: {}", getFileName(map));
                OutputStream out = new FileOutputStream(new File("/tmp/" + getFileName(map)));

                int read = 0;
                byte[] bytes = new byte[1024];
                while ((read = stream.read(bytes)) != -1) {
                    out.write(bytes, 0, read);
                }
                stream.close();
                out.flush();
                out.close();
                StringBuilder scriptOnFileUploadFinished = new StringBuilder(
                        "<script type=\"application/javascript\">\n" +
                                "      window.top.onFileUploadFinished();\n" +
                                "    </script>"
                );
                response = Response.ok(scriptOnFileUploadFinished.toString()).build();
            } catch (Exception e) {
                String error = "Ocurrio un error al subir el archivo de proveedores";
                log.error(error, e);
                response = Response.serverError().entity(error).build();
            }
        }
        return response;
    }
}

You can test this REST web service with something like postman.

It’s worth noting that we are returning a block of script tag from this web service. This is necessary to notify our client code that the file upload has finished.

Now, on the client side let’s make our code as per the docs.

final DynamicForm frmUpload = new DynamicForm();
        NamedFrame iframeUpload = new NamedFrame("iframeUpload");
        iframeUpload.setVisible(false);
        frmUpload.setTarget(iframeUpload.getName());
        frmUpload.setEncoding(Encoding.MULTIPART);
        frmUpload.setMethod(FormMethod.POST);
        UploadItem itmUpload = new UploadItem("itmProveedores", "Archivo Proveedores");
        frmUpload.setItems(itmUpload);
        frmUpload.setAction(GWT.getHostPageBaseURL() + "api/catalogos/upload");
        IButton btnUpload = new IButton("Subir archivo proveedorees");
        btnUpload.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                frmUpload.submitForm();
            }
        });

for this to work, we need to register the callback method using JSNI, let’s do that

private static void onFileUploadFinished(){
        SC.say("upload finished");
    }

    private native void registerOnFileUploadFinished()/*-{
        $wnd.onFileUploadFinished = @com.sample.CatalogosForm::onFileUploadFinished();
    }-*/;

...
/*on the constructor, load event or main entry point -it depends on your app-*/
public CatalogosForm(){
    /*initial setup*/
    registerOnFileUploadFinished();
}

and that’s it, your File should upload successfully and display a message when the upload is finished.

sources:
https://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/docs/Upload.html
http://www.javatips.net/blog/cxf-rest-file-upload?page=2
http://stackoverflow.com/questions/8488078/get-call-back-from-servlet-in-gwt-when-upload-file-in-smartgwts-dynamic-form-wi
https://webtoolkit.googleblog.com/2008/07/getting-to-really-know-gwt-part-1-jsni.html
http://stackoverflow.com/questions/2161388/calling-a-parent-window-function-from-an-iframe