Tuesday, February 2, 2021

dynamic datatable components in primefaces

I'm making notes about this here for future reference. I have an JSF application where I'm using a primefaces datatable component. 

One thing that I don't love about the current approach is that the rows in the table are domain objects in the application, and each column therefore must be a property of the object in order to display the column values. Some of the columns I want to display in the table are not naturally properties of the underlying domain object, but just temporary values associated with the task at hand. So to add them as table columns, I have to define them as properties of the object and I don't always like that. 

 More than once I've wondered if it would be better to just use a list of strings as each row in the table. This way, some of the columns might map to properties of the domain object, while others are temporary task-specific values. Anyway, I'm stashing a couple of notes here about how to do this in case I want to experiment with it later. 

Here is a snippet for displaying lists of strings as the rows for the datatable based on this thread

                            <p:dataTable id="#{rootViewId}TableContent"
                                         value="#{wizardController.rows}"
                                         rendered="true"
                                         var="row">    

                                <p:columns value="#{wizardController.rows[0]}" var="column" columnIndexVar="i">
                                    #{row[i]}
                                </p:columns>

And here is a second thread for displaying dynamically selected columns. This still uses properties on the domain object, but I wonder if I could retrieve the values from some sort of map associated with the domain object instead? Here is a snippet of the view components from that thread: 

<h:form>
    <p:selectCheckboxMenu value="#{employeeBean.selectedColumns}"
                          label="Table Columns">
        <f:selectItems value="#{employeeBean.columnMap.entrySet()}"
                       var="entry"
                       itemValue="#{entry.key}"
                       itemLabel="#{entry.value}"/>

        <p:ajax event="change" update="table"/>
    </p:selectCheckboxMenu>
    <br/>

    <p:dataTable id="table" var="emp" value="#{employeeBean.employeeList}">
        <p:columns value="#{employeeBean.selectedColumns}" var="colKey">
            <f:facet name="header">
                <h:outputText value="#{employeeBean.columnMap[colKey]}"/>
            </f:facet>
            <h:outputText value="#{emp[colKey]}"/>
        </p:columns>
    </p:dataTable>
</h:form>
And the corresponding bean code:
@ManagedBean
@ViewScoped
public class EmployeeBean {
    private List<String> selectedColumns = new ArrayList<>();
    private List<Employee> employeeList = new ArrayList<>();
    private Map<String, String> columnMap = new LinkedHashMap<>();

    @PostConstruct
    private void postConstruct() {
        initColumnProperties();
        initEmployeeList();
    }

    private void initColumnProperties() {
        addColumn("id", "ID");
        addColumn("name", "Name");
        addColumn("phoneNumber", "Phone Number");
        addColumn("address", "Address");
        selectedColumns.addAll(columnMap.keySet());
    }

    private void addColumn(String propertyName, String displayName) {
        columnMap.put(propertyName, displayName);
    }

    private void initEmployeeList() {
        DataFactory dataFactory = new DataFactory();
        for (int i = 1; i < 20; i++) {
            Employee employee = new Employee();
            employee.setId(i);
            employee.setName(dataFactory.getName());
            employee.setPhoneNumber(String.format("%s-%s-%s", dataFactory.getNumberText(3),
                    dataFactory.getNumberText(3),
                    dataFactory.getNumberText(4)));
            employee.setAddress(dataFactory.getAddress() + "," + dataFactory.getCity());
            employeeList.add(employee);
        }
    }

    public List<Employee> getEmployeeList() {
        return employeeList;
    }

    public List<String> getSelectedColumns() {
        return selectedColumns;
    }

    public void setSelectedColumns(List<String> selectedColumns) {
        this.selectedColumns = selectedColumns;
    }

    public Map<String, String> getColumnMap() {
        return columnMap;
    }
}

Friday, November 27, 2020

re-installing MacOS on macbook with bad OS install

We had a laptop that was in a bad state after a failed OS upgrade. It was trying to autoboot to the installer, but the installer claimed that the macbook didn't support that OS version. After looking up the valid latest OS version for the macbook, I followed the instructions in this macworld article to load a MacOS installer on a thumb drive and install MacOS on the broken macbook. I chose to format (erase) the hard drive using disk utility before installing MacOS.

Friday, April 24, 2020

merge latest from main git repo to my fork

This works better than a web-gui initiated pull request when there are conflicts that must be resolved manually. From this link:
# First add the upstream remote:

git remote add upstream https://repoA
git fetch upstream

# Merge in upstream changes:

git checkout master
git merge upstream/master

# Resolve conflicts and push:

git push origin master

# Your pull request should automatically update

Monday, April 6, 2020

skypeforlinux fails to run due to wrong version of libstdc++

Once again skypeforlinux fails to run, this seems to be a weekly occurrence for me. Not sure why it's so fragile. Usually it's due to the permissions problem that I documented a couple of months ago. This time, it's not finding the correct version of libstdc++. I updated the OS and installed anaconda last week, so I'm guessing it's due to one of those actions.

The error message looked like this:
$ /usr/share/skypeforlinux/skypeforlinux
A JavaScript error occurred in the main process
Uncaught Exception:
Error: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /usr/share/skypeforlinux/resources/app.asar.unpacked/node_modules/electron-utility/build/Release/electron_utility.node)
at process.func (electron/js2c/asar.js:140:31)
at process.func [as dlopen] (electron/js2c/asar.js:140:31)
at Object.Module._extensions..node (internal/modules/cjs/loader.js:922:18)
at Object.func (electron/js2c/asar.js:140:31)
at Object.func [as .node] (electron/js2c/asar.js:149:18)
at Module.load (internal/modules/cjs/loader.js:735:32)
at Module._load (internal/modules/cjs/loader.js:648:12)
at Module._load (electron/js2c/asar.js:717:26)
at Function.Module._load (electron/js2c/asar.js:717:26)
at Module.require (internal/modules/cjs/loader.js:775:19)

I found this link, and followed some instructions about using the libstdc++ installed under anaconda in the /usr/lib64 directory. Here is a summary of the steps:

strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX # to see the version of libstdc++ in your lib directory
sudo yum install libstdc++ # does nothing, yum says the package is up to date
sudo find / -name "libstdc++.so.6*" # find other installations of libstdc++, including anaconda
sudo cp /home/craig/anaconda3/lib/libstdc++.so.6.0.26 /usr/lib64/ # install libstdc++ from anaconda pkg to lib directory
sudo sudo mv /usr/lib64/libstdc++.so.6 /usr/lib64/libstdc++.so.6.bkp # make a backup of existing lib
sudo ln -s /usr/lib64/libstdc++.so.6.0.26 /usr/lib64/libstdc++.so.6 # make symlink for new lib

Friday, April 3, 2020

growing virtualbox guest centos7 linux VM on windows 10 host

Here's another thing that was a whole lot harder than it seems like it should have been. I found several threads/links that were ALMOST everything I needed to know, but missing a couple of important details that probably weren't relevant to the author's situation so not in their process.

This link is very helpful (and this one) and basically describes the correct process.

The details that were missing from the first link were:

1. modifyhd must be done for each snapshot in the VM, not just the main vdi itself (see this link):

To list all the virtualbox drives, use "c:\Program Files\Oracle\VirtualBox>VBoxmanage list hdds". Then for each one associated with the vm you are growing, use modifyhd: "c:\Program Files\Oracle\VirtualBox>VBoxmanage modifyhd "C:\Users\auto\VirtualBox VMs\craigmcc APS dev\Snapshots\{4841ac14-4e09-4b0b-aa54-9665bb1bd4b3}.vdi" --resize 50000". So in my case I used modifyhd 5 times:

c:\Program Files\Oracle\VirtualBox>VBoxmanage modifyhd "C:\Users\auto\VirtualBox VMs\craigmcc APS dev\craigmcc APS dev 20200306 1620-disk001.vdi" --resize 50000
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

c:\Program Files\Oracle\VirtualBox>VBoxmanage modifyhd "C:\Users\auto\VirtualBox VMs\craigmcc APS dev\Snapshots\{97e89522-0465-4f68-bfa9-ca33d790a379}.vdi" --resize 50000
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

c:\Program Files\Oracle\VirtualBox>VBoxmanage modifyhd "C:\Users\auto\VirtualBox VMs\craigmcc APS dev\Snapshots\{9eb0ae2e-6b3a-41ba-a212-3c27410d8dbf}.vdi" --resize 50000
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

c:\Program Files\Oracle\VirtualBox>VBoxmanage modifyhd "C:\Users\auto\VirtualBox VMs\craigmcc APS dev\Snapshots\{6b89d87f-f0d2-4a10-a64a-0b22fdde66de}.vdi" --resize 50000
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

c:\Program Files\Oracle\VirtualBox>VBoxmanage modifyhd "C:\Users\auto\VirtualBox VMs\craigmcc APS dev\Snapshots\{4841ac14-4e09-4b0b-aa54-9665bb1bd4b3}.vdi" --resize 50000
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

2. after using "lvextend" you must use "xfs_growfs" to make the space available (this is mentioned in the 2nd link above, but not the first.

After running lvextend, "lsblk" output looked correct, but "df -h" did not show the newly available space. I fixed this by running "sudo xfs_growfs /dev/mapper/centos-root". Now df shows the correct output.

So in a nutshell here are the steps:

1. make the disk partition larger, I used the command line tools shown above whereas the first link does so in vbox manager. "df" doesn't show the available space at this point, unlike the example in the first link above where df does show the space. But gparted does see it...
2. download gparted .iso file
3. mount the .iso file under the vm's storage tab on settings under IDE controller, make sure on system tab that optical is before hard disk in boot order
4. start the vm and run gparted, add the unallocated space to the partition you want to grow (in my case where / is mounted)
5. i had to follow the special LVM instructions in the first link, so in gparted you must "deactivate" the partition with the lock icon before growing it
6. unmount optical disk for gparted and reboot vm
7. display physical volumns with "sudo pvs", should show new free space
8. grow the physical volume with "sudo pvresize /dev/sda2"
9. "lsblk" still shows that the root partition is not using the entire available free space
10. run "sudo lvextend -l +100%FREE /dev/centos/root" to use the entire free space for the logical volume
11. run "sudo xfs_growfs /dev/mapper/centos-root" to grow the logical volume while mounted

Thursday, April 2, 2020

centos7 linux laptop can't connect to public wifi portals

It's not always the case, but sometimes/often I can't connect to public wifi portals from my linux laptop that open a login page automatically. The page is never displayed, and I get no internet service (though there is a wifi connection and network setup). This always happens on American Airlines and Delta flights, which is nice.

I did some research and found a couple of threads suggesting that I need to configure the NetworkManager service, and it will open the login page on the captive wifi portal. I found another link on the matter, with details about how to edit the config file. I basically did what it says, though I called the file /etc/NetworkManager/conf.d/20-connectivity-centos.conf. Supposedly this is read by the NetworkManager daemon at startup.

I restarted the daemon using these instructions, since the ones in the ubuntu threads don't work for me. I used "sudo systemctl restart NetworkManager".

Monday, March 2, 2020

virtualbox VM on centos 7 guest won't connect to network

Here's another one that I don't really understand. After working fine all last week with use all day every day, my virtualbox VM running on centos 7 guest and windows 10 host would not connect to the network. I rebooted my entire network, the guest and the host, but the problem remained. I easily found a solution with a google search, but I'm not entirely sure why it's necessary or why things worked fine last week without it. Here is the thread containing the fix, and in the end I just added the following lines to the guest file /etc/sysconfig/network-scripts/ifcfg-enp0s3:

DNS1=8.8.8.8
DNS2=8.8.4.4
# Note this was set to no
ONBOOT=yes

I restarted the guest VM, and then everything works fine.

The two DNS entries are for the Google Public DNS system. I don't know why I didn't need them last week, or why ONBOOT (which was previously set to no wasn't a problem either...