HOAB

History of a bug

Spring data and MongoDB aggregation (GroupBy)

Rédigé par gorki Aucun commentaire

Problem :

I try to create an aggregation (count and groupBy) on my documents.

Thanks to these links :

I nearly resolve my problem... nearly :)

Solution :

Documents to analyze :

  1. the _id of the application is defined by an id attribute...
  2. instance is not present is all documents
{
   phase : "Production",
   application {
      _id : 1234
   },
   instance: "myInstance"
}

The first try is to use springdata easy way : there is not groupBy ! but count is working if you need :

# If instance is set to null, returns the document which do not have the field
countByApplicationIdAndPhaseAndInstanceId(Long applicationId, Phase phase, String instance)

# Another way to test instance presence
countByApplicationIdAndPhaseAndInstanceIdExists(Long applicationId, Phase phase, Boolean exists)

So, thanks to baeldung (many thanks) ! Here is a working solution, take care about :

  1. filtering order ! the Match operation works either on the document, either on the result of the group by ! (see Baeldung example for testing result of the group by)
#Filter on document
        Aggregation aggregation = newAggregation(filterStates, agg);

#Filter on result of the aggregation
        Aggregation aggregation = newAggregation(agg, filterStates);
  1. my applicationId as used in Springdata easy way must be written with Mongo ID : application._id
  2. and application_id could not be present in the group clause as it is filtered (but as it takes me 2 long hours to make it works....)
  3. Don't forget @Id on the result bean. I see somewhere that we can execute the generic command in Mongo and do not take care about the result bean.
  4. The @Id must be on the first item of the group
  5. Do not miss the collection name in the aggregation command (here MONGO_EVALUATION_COLLECTION_NAME)
@Service
public class EvaluationAdditionalRepository {

    private static final Logger LOGGER = LoggerFactory.getLogger(EvaluationAdditionalRepository.class);

    @Autowired
    private MongoTemplate mongoTemplate;


    public List<InstanceCount> getInstanceByApplicationAndPhase(Long applicationId) {

        GroupOperation agg = group("application._id", "instanceId", "phase").count().as("countInstance");
        MatchOperation filterStates = match(new Criteria("application._id").is(applicationId));

        Aggregation aggregation = newAggregation(filterStates, agg);
        AggregationResults<InstanceCount> result = mongoTemplate.aggregate(aggregation, MONGO_EVALUATION_COLLECTION_NAME, InstanceCount.class);

        return result.getMappedResults();
    }
}

And the result bean :

import org.springframework.data.annotation.Id;

public class InstanceCount {

    @Id
    private Long applicationId;

    // Enum are authorized
    private Phase phase;

    private long countInstance;

    private String instanceId;

    public Phase getPhase() {
        return phase;
    }

    public void setPhase(Phase phase) {
        this.phase = phase;
    }

    public long getCountInstance() {
        return countInstance;
    }

    public void setCountInstance(long countInstance) {
        this.countInstance = countInstance;
    }

    public Long getApplicationId() {
        return applicationId;
    }

    public void setApplicationId(Long applicationId) {
        this.applicationId = applicationId;
    }

    public String getInstanceId() {
        return instanceId;
    }

    public void setInstanceId(String instanceId) {
        this.instanceId = instanceId;
    }

    @Override
    public String toString() {
        return "InstanceCount{" +
            ", applicationId='" + applicationId + '\'' +
            ", phase='" + phase + '\'' +
            ", instanceId='" + instanceId + '\'' +
            ", countInstance=" + countInstance +
            '}';
    }
}

 

Jmeter POST without paramter name and multipart header missing

Rédigé par gorki Aucun commentaire

Problem :

I was looking why my multipart header was not sent when suddendly, JMeter sends my POST HTTP request in a raw format.

Although I have in my GUI HTTP Request sampler a normal list of parameters : param1=value1, etc..., it sends

param1param2

 

Solution :

No solution on google, but it was "simple" : in my default HTTP Request, I changed the sheet "parameters" to "body data", even if the both was empty it was sufficient to invite chaos...

The first problem was that my Multipartform-data header was not sent : because a default one was set on default HTTP Header...

End of day....

 

 

Antivirus et transfert de fichiers bloqué

Rédigé par gorki Aucun commentaire

Le problème :

Quand on est chez le client, il arrive qu'on doive transférer des fichiers dans un environnement "sécurisé". Il existe parfois des solutions de transfert :

  • espace de partage sécurisé (permet de logguer les transferts)
  • clé usb chiffrée

Et puis de temps en temps c'est galère (la clé n'est pas là, le transfert n'est pas accessible, ...) et votre fichier doit arriver chez le client. Or les .sh, .jar, .zip, .exe, sont mal vu... Normal. Les dropbox wetransfer, et autre FTP bannis, le partage WIFI bloqué, les fichiers scannés...

Pour autant la plupart des sites sont autorisés pour le travail (normal aussi).
 

Solution :

Il vous faut :

  • une habilitation sur un poste client (sinon pourquoi voudriez-vous envoyer des fichiers ?)
  • un espace disponible sur internet

Utilisez ce petit programme :

  • côté pile : on rajoute du bruit avant le fichier à télécharger. On met ce fichier sur un espace internet
  • côté face : on télécharge le fichier depuis cet espace neutre, on enlève le bruit

Si c'est un vrai virus, l'antivirus le verra lors de l'écriture du fichier sans bruit (enfin, on peut l'espérer). LE fichier n'est pas exécutable sans le "unhide", donc il faut une action humaine pour ça, donc ça limite parfaitement les risques.

Ca limite les risques, parce que si vous arrivez à faire exécuter ça à quelqu'un (transfert, compilation, téléchargement, unhide, exécution) alors vous avez largement les moyens de faire autre chose de mieux au niveau piratage.... social hacking.

Quand à savoir pourquoi on ne peut pas télécharger un fichier mais quand même l'exécuter, ça....

Ca dépanne de temps en temps.

package com.hidefile;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

import static java.lang.System.exit;

public class Hider {
    private static final byte[] bytes = "unelongueclepourquelesantivirusenaitmarrederegarder".getBytes();

    public static void hide(String filename) {
        try {
            String destFilename = filename + ".mdfy";
            ReadableByteChannel rbc = Channels.newChannel(new FileInputStream(filename));
            FileOutputStream fos = new FileOutputStream(destFilename, false);
            fos.write(bytes);
            fos.getChannel().transferFrom(rbc, bytes.length, Long.MAX_VALUE);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void unhide(String filename) {
        try {
            String destFilename = filename.replace(".mdfy", "");
            FileInputStream fis = new FileInputStream(filename);
            ReadableByteChannel rbc = Channels.newChannel(fis);
            FileOutputStream fos = new FileOutputStream(destFilename, false);
            System.out.println("bytes.length = " + bytes.length);
            fis.skip(bytes.length);
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String... args) {
        if (args.length != 2) {
            System.err.println("Bad arguments : --hide|-h|--unhide|-u ");
            exit(1);
        }

        if (args[0].equals("-u") || args[0].equals("--unhide") ) {
            unhide(args[1]);
        }
        else {
            hide(args[1]);
        }
    }


}

Astuce, les extensions sont importantes : .png passe mieux que .jar.mdfy

Au pire, le bruit peut être un header PNG :

private static final byte[] bytes = new byte[]{(byte) 137,80,78,71,13,10,26,10};

Bien sur c'est en total non-conformité avec la charte d'utilisation de votre poste en général.

Spring Boot ne sert pas les ressources statiques

Rédigé par gorki Aucun commentaire

Le problème :

Avec une stack JHipster, spring-boot n'affiche pas les ressources statiques en mode développement.

Ddonc par exemple pas de index.html...

Pour autant si on lance la commande avec le war serverless (cf spring-boot-maven-plugin), ça fonctionne.

Je suis sous Intellij, à l'évidence quelque chose manque dans le lancement de la tâche Intellij spring-boot

L'architecture est mavenisé donc le root contexte est sous : src/main/webapp

Cependant spring-boot semble chercher ses ressources ailleurs : cf la documentation

Par quelle magie spring-boot doit-il trouver ses ressources dans src/main/webapp ??

Solution :

Beaucoup de recherches, de debug et autre (il y a un peu de spring-secu dans le lot). Au final les services jhipster classiques (health, dump, etc...) fonctionnent mais toujours pas de ressources statiques.

Vérification :

  • de la tâche de lancement Intellij, elle semble correcte.
  • des classpaths (on met src/main/webapp dans le classpath, on l'enlève) 
  • des paramètres de lancement (profil Spring et autre)

Au final la mise en debug m'a permis de trouver un log perdu parmi les autres :

[DEBUG] org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory - None of the document roots [src/main/webapp, public, static] point to a directory and will be ignored.

Tiens donc le Tomcat embarqué de spring-boot a ses propres chemins de recherches... (pas tout à fait décrit dans la doc Spring ci-dessus).

Breakpoint, watch, et paf, le chemin vers src/main/webapp en absolu n'est pas le bon.

Tout ça parce que le répertoire de travail de ma tâche spring-boot sous Intellij n'était pas fixé. Comment Intellij détermine cette valeur ? Mystère. En mettant donc le répertoire de travail égal au répertoire qui contient le src/main/webapp, tout roule.

[DEBUG] org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory - Document root: /home/qwbt2550/projets/portailLCRI/lcri-portal/src/main/webapp

 

 

Java threaddump sous windows

Rédigé par gorki Aucun commentaire

Problème :

Faire des threadumps un peu assisté pour Java sous Windows. Normalement, il faut :

  • repérer le pid
  • appeler jstack sur le pid
  • stocker le résultat dans un fichier unique

Mais j'avais besoin d'un script oneshot que les utilisateurs puissent lancer facilement et plusieurs fois

Solution :

Merci aux différentes ressources du net, voici un petit script rapide :

@echo off

SET JAVA_HOME=c:\Program Files\Java\jdk1.7.0_51\
SET OUTPUT_DIR=c:\temp\lzg_threaddumps
SET COMMAND_TO_CHECK=java.exe

setlocal enableextensions
if not exist "%OUTPUT_DIR%" md "%OUTPUT_DIR%"
endlocal

for /f "tokens=2" %%F in ('tasklist /nh /fi "imagename eq %COMMAND_TO_CHECK%"') do (


    SET DEST_FILE="%OUTPUT_DIR%\%%F_%date:~-4,4%%date:~-7,2%%date:~-10,2%_%time:~-11,2%%time:~-8,2%%time:~-5,2%%time:~-2,2%.txt"
    @echo Dumping %%F to file %DEST_FILE%
    rem echo "%JAVA_HOME%\bin\jstack.exe" %%F
    "%JAVA_HOME%\bin\jstack.exe" %%F > %DEST_FILE%
)

 

 

Fil RSS des articles de cette catégorie