Il cittadino al centro.

Questo 2024 verrà sicuramente ricordato per la scomparsa del nostro amato ex sindaco Ing. Tullio Ferrari, sindaco che, come il sottoscritto, ha vissuto con passione ed impegno il quotidiano lavoro dell’amministratore pubblico e di cui la nostra comunità conserva un dolce ricordo. Ho voluto per questo lasciare a lui la copertina di questo numero de “La Loggia” dopo aver parlato con la figlia Alessia che mi ha raccontato l’aneddoto dietro questa foto. Tullio riteneva infatti che un albero così longevo che cade è un momento storico da immortalare. Ed eccolo li, sorridente con il suo fidato Zeus che, mentre si faceva fotografare, ha probabilmente ripensato a tutti gli anni trascorsi guardando fuori dalle finestre del municipio, a tutti i passi percorsi, a tutte le telefonate, alle parole scritte, dettate, gridate, ai successi e agli errori.

E’ stato proprio a seguito di questa foto che ho ripreso ad interrogarmi sulla professione del sindaco, professione interessante la nostra, fatta di compromessi, di battaglie quotidiane per spostare di un millimetro avanti il baricentro degli obiettivi che ci si è prefissi. A queste continue riflessioni, che ora mai mi accompagnano da 8 anni a questa parte, si è aggiunto l’articolo sulla stampa locale in cui si parla di Minerbe come paese a rischio estinzione e che fa riferimento ad uno studio della Regione del Veneto chiamato “Il nuovo piano di riordino territoriale”. 

In tale rapporto si evince che Minerbe è il secondo comune nella regione più a rischio e che necessita di essere fuso con altri comuni. Comprenderete, cari lettori, quanto questo sia frustrante ed umiliante per un amministratore, un commerciante, un imprenditore, un lavoratore, un cittadino, apprendere della gravita di questa situzione e questo sentimento mi ha infatti accompagnato per alcuni giorni e tuttora mi perseguita. Superato lo shock iniziale però, mi sono ricordano che prima di tutto sono un uomo di numeri ed ho cercato di approfondire la questione e, controllando il rapporto completo (disponibile sul sito della regione), ho immediatamente notato che alcuni dati non tornavano ed in un caso non erano corretti.

Ora, come ben sapete i dati sono l’oro del nuovo millennio ma, da soli, valgono poco. Devono essere analizzati ed immersi nel contesto. Accompagnatemi in questa analisi. Stando a quanto dice questo rapporto, Minerbe aveva una popolazione nel 2021 (data ultimo censimento) di 4.534 abitanti in calo rispetto al 2011, calo che nella tabella riepilogativa è indicato al -3.7% ma nella realtà (stando al dato fornito dalla regione poche pagine prima) è del -2.8%, ovvero di poco sotto alla media regionale del -2.9%. La cosa che però sorprende di più è il criterio usato per considerare un comune a rischio, ovvero la spesa corrente.

Come sapete la spesa corrente è quella parte di entrate ed uscite di un bilancio comunale che serve a finanziare la gestione ordinaria. Rientrano in questa parte del bilancio le spese di manutenzione, gli interessi sui mutui (ad oggi attorno a 500.000 euro/anno nel 2024 contro i ), i contributi alle famiglie, alle associazioni, alle attività sportive, gli acquisti, la spesa del personale. Ora, Minerbe spende 656 euro a abitante per fornire servizi, mentre la media regionale è 610. La pressione tributaria procapite a Minerbe è di 321 euro contro i 371 euro della media regionale. Ecco la criticità, Minerbe spende troppo, ma dove spende troppo? Nell’erogare servizi ai cittadini! Questo a mio avviso è un vanto, e sicuramente siamo in grado di erogare molti servizi gravando sul cittadino meno della media degli altri comuni del veneto. Siamo puniti perché virtuosi? Spendiamo molto e facciamo poco avanzo? Probabilmente si. Probabilmente per Roma e per Venezia, questo è un dato che va corretto ma non secondo questa amministrazione! Forse il problema della crescita è legato anche all’assenza di case disponibili, se date un’occhiata al centro del paese noterete quante ve ne siano di disabitate. 

Come dice il titolo, il cittadino è al centro, al centro della nostra attività amministrativa e tale deve restare! Minerbe, secondo questi esperti dovrebbe già stare sui libri di storia, dimenticato, sorvegliato speciale perché si svuota. Dal 2011 ad oggi (2024) abbiamo avuto 532 nati, 749 decessi, 135 emigrati ma soprattutto 1364 nuovi arrivati (persone che hanno stabilito la propria residenza a Minerbe). La verità è che Minerbe non si svuota: semplicemente non ha mai avuto folle oceaniche. È un paese vivo, con molti servizi, molti negozi, molte imprese, con tre banche, un ufficio postale, una caserma dei carabinieri, una scuola, due asili. È un paese con la sua dimensione, i suoi ritmi, i suoi pregi e difetti. E se proprio vogliamo parlare di problemi, forse sarebbe il caso di ascoltare la comunità, anziché arrivare a conclusioni poco sensate da qualche ufficio ben lontano. Altrimenti, come sindaco, mi sento di dire: “ringraziamo per la diagnosi… ma il paziente sta benissimo, grazie”. 

Minerbe non sarà la metropoli dei sogni in cui tutto è perfetto, non ci sarà la fila di giovani pronti ad entrare, ma nemmeno il cartello “L’ultimo spenga la luce”. 

C’era una volta lo scorrere placido dei fiumi

L’alluvione dell’Emilia-Romagna del 2023 comprende una serie di eventi alluvionali e geologici prodotti da un fronte meteorologico occluso di origine atlantica, alimentato a sua volta da un ciclone mediterraneo, che ha generato sulla regione piogge persistenti, allagamenti, straripamenti e frane dal 2 al 17 maggio 2023. I dati dell’evento alluvionale romagnolo sono impressionanti:

– 23 fiumi esondati, i punti di esondazione sono oltre 50, 
– oltre 500 frane,
– Pioggia che, racchiusa in 4 giorni (1-2-16-17 maggio) ha superato perfino il piovosissimo maggio 1939.

La manutenzione, che è sacrosanta, va bene per far fronte ad eventi moderati. Quello sopra sintetizzato è tutto tranne che moderato. Se non si analizza il problema partendo da questo fatto, sarà difficile trarre qualche ragionamento serio. Evidentemente il sistema di scolo delle acque, con fiumi ristretti nel tempo, i cui tratti arginati sono stati costruiti molto tempo fa, non sono più sufficienti a far defluire questi carichi idraulici. C’è poco da fare, con questo assetto territoriale, la questione è diventata ingestibile, soprattutto nei confronti dell’attuale e futuro regime di precipitazioni piovose. In parole povere tutto il sistema idraulico di gestione delle acque piovane non è più in grado di fronteggiare eventi atmosferici di portata media – intensa. A questo si deve aggiungere, purtroppo, la cattiva gestione, in alcuni casi totale assenza, delle acque piovane da parte dei privati in quanto, l’acqua piovana della propria abitazione o terreno andrebbe scaricata nella rete e non sulla strada.

E sulla pulizia dei fiumi quindi? Questo concetto precotto, che ogni volta viene ripetuto fino allo sfinimento, trae la sua origine in una distorsione storica, ovvero che “una volta” si facesse manutenzione. In realtà non è così, ma molto semplicemente “una volta” i fiumi godevano di maggior rispetto da parte dell’uomo, come il territorio ad essi circostante. Dal secondo dopoguerra in poi, i fiumi sono stati visti come cave a cielo aperto per inerti, sabbie e ghiaie, e aree di scolo in cui far transitare il più velocemente possibile le acque dai rilievi al mare.

Questo ha fatto si che, soprattutto relativo alle gigantesche estrazioni di sedimenti in alveo, i fiumi iniziassero un processo di incisione dell’alveo stesso, attraverso il fenomeno di erosione che si manifesta sia in maniera regressiva, ovvero a monte di dove io ho estratto i sedimenti, che progressiva, a valle del punto di estrazione.
I fiumi sono andati incontro quindi ad un processo di canalizzazione innaturale che ha portato numerosissimi problemi con sé, tra cui: aumento della velocità della corrente, aumento dell’incisione, minor espansione e, soprattutto, minor ricarica delle falde acquifere. Un esempio evidente sono gli isolotti che si sono formati sul fiume Adige ben visibile transitando su ponte Limoni o, la scomparsa dell’isola una volta ben visibile da ponte Principe Umberto di Legnago. L’aumento della velocità della corrente, porta ad un evidente problema di ricarica delle falde acquifere che avviene principalmente per contatto quindi, il fiume accelerando la sua corsa, rilascia pochissima acqua sulle falde sottostanti aggravando il problema della siccità.

La pulizia risolve tutto? Bisogna definire cosa si intende per pulizia: l’unica pulizia fluviale che ha senso è la rimozione del legname secco in quanto quello viene subito preso in carico dalle piene e potrebbe creare sbarramenti in sezioni critiche come, ad esempio, ostruire la luce di un ponte. Il resto, sono leggende metropolitane. Gli alberi “vivi” rappresentano una difesa idraulica passiva, in quanto sono in grado di far rallentare la corrente idraulica. Pensate che dove non ci sono, vengono impiantate delle opere di ingegneria con la stessa funzione degli alberi, detti pennelli. Purtroppo però non vanno abbandonate e necessitano di continua manutenzione, compresa la potatura e la sostituzione.

Il problema principale legato ai fiumi è che la sezione è ridotta sempre più all’osso, ovvero ridotta la larghezza al minimo senza lasciare la possibilità all’acqua di riappropriarsi di terreni ma, soprattutto, paghiamo la cementificazione e di conseguenza l’impermeabilizzazione dei terreni. Ad esempio, un area di un chilometro quadrato a terreno naturale assorbirà più o meno acqua a seconda della sua composizione ma, nel caso venga coperta da materiale impermeabile come cemento o asfalto, dove andrà l’acqua che piove? Non verrà mai assorbita e finirà velocemente nelle reti scolanti, quindi nei canali ed infine nei fiumi. Si, quei fiumi che già li abbiamo ristretti e poi caliamo giù l’asso come surplus idrico da gestire. E le precipitazioni intense, concentrate, degli eventi estremi mettono la ciliegina sulla torta. Questo concetto vale per i fiumi ma vale anche per le nostre case. Molto spesso, analizzando i problemi di chi ha subito allagamenti, scopriamo che buona parte della capacità di catturare acqua da parte del terreno è stata compromessa a causa di lavori domestici che lo hanno impermeabilizzato. 

A questo punto è d’obbligo chiedersi cosa possiamo fare per provare a prevenire o contenere i problemi. Vanno aumentate le golene, va dato spazio ai fiumi di potersi allargare, vanno ripristinate le aree tampone, vanno riaperti tutti i canali di scolo, vanno risolte le criticità dovute alle impermeabilizzazioni del suolo come serre o affini. Dobbiamo tornare ad un piano di gestione e conservazione delle acque di territorio abbandonando il sistema a canale singolo modello “canale scolante” come li vediamo ora.

L’acqua è un bene prezioso e dobbiamo occuparcene tutti. Il Comune può e deve fare molto, ma serve l’aiuto di tutti, soprattutto nella responsabilizzare lo scarico ricordando che le strade non sono fiumi, i canali di scolo non sono fiumi, ed i fiumi vanno rispettati. Se non capiamo questo concetto sarà sempre peggio: la cementificazione e il cambiamento climatico comportano un notevole surplus idrico che i fiumi, ristretti fino all’osso, non riusciranno mai a smaltire e le conseguenze sono sotto gli occhi di tutti.

Java: Pass By Value or Pass By Reference

Data is shared between functions by passing parameters. Now, there are 2 ways of passing parameters:

  • Passing by value: this method copies the value of actual parameter. The called function creates its own copy of argument value and the use it inside the code. As soon as the work is done on the copied value, the original parameter does not see any change.
  • Passing by reference: the pass by reference method passes the parameters as a reference(address) of the original variable. The called function does not create its own copy, rather, it refers to the original values only. Hence, the changes made in the called function will be reflected in the original parameter as well.

Java follows the following rules in storing variables:

  • Local variables like primitives and object references are created on Stack memory
  • Objects are created on Heap memory

Java always passes arguments by value, NOT by reference.

So how is it that anyone can be at all confused by this, and believe that Java is pass by reference, or think they have an example of Java acting as pass by reference? The key point is that Java never provides direct access to the values of objects themselves, in any circumstances. The only access to objects is through a reference to that object. Because Java objects are always accessed through a reference, rather than directly, it is common to talk about fields and variables and method arguments as being objects, when pedantically they are only references to objectsThe confusion stems from this (strictly speaking, incorrect) change in nomenclature.

So, when calling a method:

  • For primitive arguments (intlong, etc.), the pass by value is the actual value of the primitive (for example, 3)
  • For objects, the pass by value is the value of the reference to the object

So if you have doSomething(foo) and public void doSomething(Foo foo) { .. } the two Foos have copied references that point to the same objects.

Naturally, passing by value a reference to an object looks very much like (and is indistinguishable in practice from) passing an object by reference.

Tagged

Return Distinct Values for an Array Field

The following example returns the distinct values for the field sizes from all documents in the Collection1 collection:

db.getCollection('inventory').distinct('storeCode')

This will be the expected result:

[
     "1502", "1002", "747"
]

Distinct, as for relational database, finds the distinct values for a specified field across a single collection or view and returns the results in an array.

Tagged

Algorithm complexity and Big O notation

Every system transform data into output and that’s why is important to understand the efficiency of our algorithms and data structures according to each solution. 

Big O Notation measures the efficiency of an algorithm according to its time and space complexities. The input size of a function can increase linearly and we should be aware of what’s is going to happen with the system in the worst-case scenario. Time complexity is denoted O(…) where the three dots represent some function. Usually, the variable n denotes the input size.

The commonest runtime complexities are: 

  • O(1) Constant Runtime: the running time of a constant-time algorithm does not depend on the input size
  • O(log n) A logarithmic algorithm often halves the input size at each step. The running time of such an algorithm is logarithmic because log2 n equals the number of times n must be divided by 2 to get 1.
  • O(n) A linear algorithm goes through the input a constant number of times.
  • O(n log n) This time complexity often indicates that the algorithm sorts the input because the time complexity of efficient sorting algorithms is O(n log n). Another possibility is that the algorithm uses a * data structure where each operation takes O(log n) time
  • O(n^2) A quadratic algorithm often contains two nested loops
  • O(n^3) A cubic algorithm often contains three nested loops
  • O(2^n) This time complexity often indicates that the algorithm iterates through all subsets of the input elements. For example, the subsets of {1, 2, 3} are ∅, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, and {1, 2, 3}
  • O(n!) This time complexity often indicates that the algorithm iterates through all permutations of the input elements. * For example, the permutations of {1, 2, 3} are (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), and (3,2,1).

And why should we care about Big O Notation? For large applications that manipulate a large amount of data, it’s really important to perform this analysis since inefficient algorithms will impact the performance of the system.  Be aware of the effect of the data structures that you’re using in an algorithm since each one manipulates data in memory and performs operations in different ways.

NP-hard problems are an important set of problems, for which no polynomial algorithm is known.

Tagged , ,

SARS-CoV-2 e Disinfezione delle strade

TL;DR (se avete fretta, cosa che è assolutamente errata quando ci si deve informare, saltate subito alla parte finale con scritto MORALE).

Torno sull’argomento. Fin da subito mi sono schierato contro questa pratica inquinate e pericolosa ricevendo anche qualche critica ma, ho troppo rispetto per la mia comunità per prendere decisioni che accontentano e portano facile consenso sebbene non siano corrette.

Amministrare vuol dire anche prendere decisioni difficili e avere il coraggio di spiegarle, farle capire portando dati a suffragio e portarle avanti. Dopotutto, quante decisioni strategiche per la nazione sono state sacrificate sull’altare del consenso elettorale?

Non è stato un capriccio il mio, ma semplicemente mi sono informato sul sito di IIS, OMS, ho parlato con esperti, ho letto tanti articoli scientifici (e non Donna Moderna), ho contattato la Federation of American Scientists per un parere, e grazie ai miei genitori e ai miei sforzi, ho costruito delle solide basi scientifiche che mi permettono di avere opinioni che siano basate su fatti, dati, osservazioni e non su emozioni o impressioni.

Purtroppo la scienza è antidemocratica, impopolare, non può essere compresa da tutti, alla scienza non importa dell’opinione del singolo, ma la scienza ti salva la vita. E la scienza, ha fin da subito detto che spruzzare disinfettante per le strade è inutile e dannoso per combattere una pandemia.

Seguite SEMPRE la scienza. Chiunque creda di fornire verità alternative che la scienza vuole censurare è solo un cialtrone, non un novello Galileo. Come disse qualcuno più importante di me, per essere un novello Galileo non bisogna solo dire il contrario di ciò che sostengono gli altri, bisogna pure avere ragione ma soprattutto dimostrarlo sulla base del metodo scientifico.

MORALE: per quanto esposto qui sopra, sui seguenti link, a Minerbe (VR) NON VERRA’ FATTA LA DISINFEZIONE DELLE STRADE in quanto vi sono evidenze a supporto dell’utilità della disinfezione con prodotti chimici pericolosi, come l’ipoclorito di sodio di strade e pavimentazioni esterne. Tutto il resto è solo show elettorale.

[1] https://www.epicentro.iss.it/coronavirus/pdf/rapporto-covid-19-7-2020.pdf

[2] https://www.sciencemag.org/news/2020/03/does-disinfecting-surfaces-really-prevent-spread-coronavirus?fbclid=IwAR313l6shJ9oluX9gyT0T9sswuyjVXGKk15gSxmdGOemc6DA3lMPnKr3Tcc

Spring 4+ with Ehcache 3.x

This post describes an example of using Ehcache with a Spring MVC application deployed on Tomcat (not using Spring boot). It is a legacy app that needs to be upgraded.

The dependencies are:

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
    <version>1.1.1</version>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.8.1</version>
</dependency> 

Application context must be updated in this way:

<!-- ***** CACHE CONFIGURATION v.3 ***** -->
<cache:annotation-driven cache-manager="ehCacheManager" />
<bean id="ehCacheManager" class="org.springframework.cache.jcache.JCacheCacheManager">
  <property name="cacheManager">
    	<bean class="org.springframework.cache.jcache.JCacheManagerFactoryBean" 
        p:cacheManagerUri="classpath:ehcache.xml" />
  </property>
</bean>

The method must be annotated with @Cacheable so that Spring will handle the caching. As a result of this annotation, Spring will create a proxy of the NumberService to intercept calls to the square method and call Ehcache.

This is how to annotate the method (a service or a Dao implementation) providing the cache alias and the key for the cache:

@Cacheable(value = "retrieveUserIdOfMYGroup", key = "#userId")
public ArrayList<Integer> retrieveUserIdOfMYGroup(int userId) {
    [...]
}

Now, ehcache.xml config that is completely different than the previous version of ehcache (this is a simple config):

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.ehcache.org/v3"
    xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
    xsi:schemaLocation="
            http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
            http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
	
	<cache-template name="myDefaults">
	<listeners>
            <listener>
                <class>com.afm.web.configuration.CacheLogger</class>
                <event-firing-mode>ASYNCHRONOUS</event-firing-mode>
                <event-ordering-mode>UNORDERED</event-ordering-mode>
                <events-to-fire-on>CREATED</events-to-fire-on>
                <events-to-fire-on>EXPIRED</events-to-fire-on>
                <events-to-fire-on>EVICTED</events-to-fire-on>
            </listener>
        </listeners>        
	</cache-template>
	
	<!-- @Cacheable(value = "retrieveUserIdOfMYGroup", key = "#userId") -->
	<cache alias="retrieveUserIdOfMYGroup" uses-template="myDefaults">
		<heap unit="entries">200</heap>
	</cache>
            
</config>

Cache listeners allow implementers to register callback methods that will be executed when a cache event occurs and print on the log appender. This is how class CacheLogger is implemented:

public class CacheLogger implements CacheEventListener<Object, Object> {

  protected final Log LOG = LogFactory.getLog(getClass());
	
	@Override
	public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
		LOG.info("Key: " + cacheEvent.getKey()  
      + " | EventType: " + cacheEvent.getType() 
      + " | Old value: " + cacheEvent.getOldValue() 
      + " | New value: " + cacheEvent.getNewValue());		
	}

}
Tagged , ,

React.js: fill options of Autocomplete with API results

The autocomplete is a normal text input enhanced by a panel of suggested options.  Autocomplete is a feature that helps in predicting the rest of the word typed by a user. Autocomplete is helpful from the user as well as the user experience perspective. It makes users happy by saving their time and also by offering them several choices.

In this case, I fill the Autocomplete with the results of Google Ads locations an this is the expected result:

For first, import Autocomplete component (of course must be installed):

import Autocomplete from '@material-ui/lab/Autocomplete';
// or
import { Autocomplete } from '@material-ui/lab';

Define the object that will be used to collect the Autocomplete options:

const locationResults = [];

This is how Autocomplete is defined:

let autocompleteBox = <Grid item xs={12} md={12} sm={12} lg={12}>
    <Autocomplete
        id="autocompleteLocations"
        value={this.state.autocompleteValue}
        options={locationResults} 
        getOptionLabel={option => option.locationName}      
        autoHighlight={true}   
        autoSelect={true}                    
        style={{ width: 600, marginTop: 20 }}                        
        clearOnEscape                        
        onChange={(event, autocompleteValue) => this.setState({ autocompleteValue })}
        renderInput={params => <TextField {...params} label="Search location" variant="outlined" onChange={this.handleAutocompleteTextChange.bind(this)} />}
    />

    </Grid>;

Once the user enters some text on Search location TextField, this function is called (I expect user inserts at least 3 chars before call the API):

/**
 * On change text of Autocomplete
 */
handleAutocompleteTextChange = (event) => {

    this.setState({
        query: event.target.value
    }, () => {

        if (this.state.query && this.state.query.length > 3) {
            this.getLocations(this.state.query);
        }
    })
}

This is how the function getLocations() is implemented:

/*
 * API Function to retrieve locations
 */
getLocations = (locationQuery) => {

    axios(
        {
            method : 'get', url: GET_LOCATIONS, auth: this.state.userInfo.apiAuth, params: {
            user: this.state.userInfo.username,
            customerId: this.state.clientCustomerId,
            query: locationQuery
        }
    }).then(res => {

        if (res.status == 200) {
            this.setState({results: res},()=>{
                this.forceReloadOrganization(res)
            });
        } else {
            this.setState({results: []});
        }

    }).catch(error => {
        this.setState({results: []});
        console.log(JSON.stringify(error));
    });

}

The last thing is to update the options on Autocomplete:

/**
 * Reload the results after API call
 */
forceReloadOrganization = (results) => {
    {

        if ( results.data != "" ) {
            results.data.map(item => {

                locationResults.push({
                        id:item.location.id,
                        type: item.location.displayType,
                        locationName:item.canonicalName + ": " + item.location.displayType + " (" + item.location.id + ")"
                    }
                )
            });
        }

    }
}
Tagged ,

Mongo Replica set with docker-compose

replica set in MongoDB is a group of mongod processes that maintain the same data set. Replica sets provide redundancy and high availability and are the basis for all production deployments. Replication provides redundancy and increases data availability. With multiple copies of data on different database servers, replication provides a level of fault tolerance against the loss of a single database server. A replica set contains several data bearing nodes and optionally one arbiter node. Of the data-bearing nodes, one and only one member is deemed the primary node, while the other nodes are deemed secondary nodes.

The primary node receives all write operations. A replica set can have only one primary capable of confirming writes with { w: "majority" } write concern. By default, clients read from the primary [1]; however, clients can specify a read preference to send read operations to secondaries.

Doing it with docker-compose is pretty simple. The first step is to create the docker-compose.yml configuration file:

version: "3"
services:
  mongo1:
    hostname: mongo1
    container_name: localmongo1
    image: mongo:latest
    volumes:
      - mongodb1-data:/data/db
      - mongodb1-config:/data/configdb
    expose:
    - 27017
    ports:
      - 27011:27017
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
  mongo2:
    hostname: mongo2
    container_name: localmongo2
    image: mongo:latest
    volumes:
      - mongodb2-data:/data/db
      - mongodb2-config:/data/configdb
    expose:
    - 27017
    ports:
    - 27012:27017
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
  mongo3:
    hostname: mongo3
    container_name: localmongo3
    image: mongo:latest
    volumes:
      - mongodb3-data:/data/db
      - mongodb3-config:/data/configdb
    expose:
    - 27017
    ports:
    - 27013:27017
    restart: always
    entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]

volumes:
  mongodb1-data: {}
  mongodb1-config: {}
  mongodb2-data: {}
  mongodb2-config: {}
  mongodb3-data: {}
  mongodb3-config: {}
  proftpd-home: {}

At this point, docker must be started:

$ docker-compose up 
# or
$ docker-compose up -d

At this point, enter in one mongo bash and access to mongo console:

$ docker exec -it localmongo1 /bin/bash
$ mongo

The last step is to run the DB replica set initialization:

rs.initiate(
  {
    _id : 'rs0',
    members: [
      { _id : 0, host : "mongo1:27017" },
      { _id : 1, host : "mongo2:27017" },
      { _id : 2, host : "mongo3:27017" }
    ]
  }
)

Now, mongo is ready to accept a connection on port 27011 and, as soon as a DB / collection / document is created or updated, it will be replicated on secondary servers.

Tagged ,

Java: Sort a list of objects according to matching string/pattern

I need to sort a list of objects in which the matching items come up and others will go down so. For instance, a list of objects on which all the labels are in alphabetical order except for all the values that start with P that will be put on the top of the list.

I just need to create a new Comparator class instead of creating an anonymous Comparator, like this:

Collections.sort(result, new Comparator< MyObject>() {
    @Override
    public int compare(final MyObject o1, final MyObject o2) {
 
        // Special case to put "P" in front of the list
        if(o1.getLabel().startsWith("P")) {
            return o1.getLabel().startsWith("P}")? o1.getLabel().compareTo(o2.getLabel()): -1;
        } else {
            return o2.getLabel().startsWith("P")? 1: o1.getLabel().compareTo(o2.getLabel());
        }
 
    }
});

On which MyObject is defined in this way:

class MyObject {
    private String label;
    private String value;
    
    // getter an setter
}
Tagged